@bpmn-io/form-js-editor 0.12.2 → 0.13.1
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/README.md +0 -3
- package/dist/assets/form-js-editor-base.css +486 -0
- package/dist/assets/form-js-editor.css +1161 -60
- package/dist/index.cjs +1247 -526
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +1249 -528
- package/dist/index.es.js.map +1 -1
- package/dist/types/FormEditor.d.ts +9 -0
- package/dist/types/core/FormFieldRegistry.d.ts +1 -1
- package/dist/types/core/FormLayoutValidator.d.ts +16 -0
- package/dist/types/core/FormLayouter.d.ts +1 -0
- package/dist/types/core/index.d.ts +8 -4
- package/dist/types/features/dragging/Dragging.d.ts +60 -0
- package/dist/types/features/dragging/index.d.ts +6 -0
- package/dist/types/features/editor-actions/index.d.ts +1 -1
- package/dist/types/features/expression-language/index.d.ts +8 -0
- package/dist/types/features/keyboard/index.d.ts +1 -1
- package/dist/types/features/modeling/FormLayoutUpdater.d.ts +13 -0
- package/dist/types/features/modeling/Modeling.d.ts +7 -7
- package/dist/types/features/modeling/behavior/index.d.ts +3 -3
- package/dist/types/features/modeling/cmd/Util.d.ts +1 -0
- package/dist/types/features/modeling/index.d.ts +3 -1
- package/dist/types/features/palette/index.d.ts +1 -1
- package/dist/types/features/properties-panel/entries/ColumnsEntry.d.ts +2 -1
- package/dist/types/features/properties-panel/entries/InputKeyValuesSourceEntry.d.ts +1 -1
- package/dist/types/features/properties-panel/entries/SelectEntries.d.ts +1 -0
- package/dist/types/features/properties-panel/entries/factories/simpleBoolEntryFactory.d.ts +1 -0
- package/dist/types/features/properties-panel/groups/GeneralGroup.d.ts +1 -1
- package/dist/types/features/properties-panel/groups/LayoutGroup.d.ts +11 -0
- package/dist/types/features/properties-panel/groups/index.d.ts +1 -0
- package/dist/types/features/properties-panel/index.d.ts +1 -1
- package/dist/types/features/selection/index.d.ts +2 -2
- package/dist/types/import/Importer.d.ts +4 -2
- package/dist/types/import/index.d.ts +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/render/EditorFormFields.d.ts +1 -1
- package/dist/types/render/components/FieldDragPreview.d.ts +1 -0
- package/dist/types/render/components/editor-form-fields/EditorText.d.ts +1 -1
- package/dist/types/render/components/editor-form-fields/index.d.ts +1 -1
- package/dist/types/render/components/icons/index.d.ts +1 -1
- package/dist/types/render/hooks/index.d.ts +3 -0
- package/dist/types/render/hooks/useDebounce.d.ts +1 -0
- package/dist/types/render/hooks/usePrevious.d.ts +1 -0
- package/dist/types/render/index.d.ts +2 -2
- package/package.json +10 -8
- package/dist/assets/dragula.css +0 -22
- package/dist/assets/properties-panel.css +0 -1016
package/dist/index.es.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { FormFieldRegistry as FormFieldRegistry$1, clone, iconsByType,
|
|
1
|
+
import { FormFieldRegistry as FormFieldRegistry$1, clone, iconsByType, Text as Text$1, FormFields, formFields, FormContext, FormRenderContext, FormComponent, FormLayouter, getSchemaVariables, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_PATHS, VALUES_SOURCES_LABELS, FeelExpressionLanguage, FeelersTemplating, createFormContainer, createInjector, MarkdownModule, schemaVersion } from '@bpmn-io/form-js-viewer';
|
|
2
2
|
export { schemaVersion } from '@bpmn-io/form-js-viewer';
|
|
3
3
|
import Ids from 'ids';
|
|
4
4
|
import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, set as set$1, isUndefined, without, has, isString } from 'min-dash';
|
|
5
5
|
import classnames from 'classnames';
|
|
6
|
-
import { jsx, jsxs } from 'preact/jsx-runtime';
|
|
7
|
-
import { createContext, render, createElement } from 'preact';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'preact/jsx-runtime';
|
|
8
7
|
import { useContext, useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect } from 'preact/hooks';
|
|
9
|
-
import
|
|
8
|
+
import { createContext, render, createElement } from 'preact';
|
|
10
9
|
import React, { forwardRef } from 'preact/compat';
|
|
10
|
+
import dragula from 'dragula';
|
|
11
11
|
import { classes, closest, event, matches, domify, query } from 'min-dom';
|
|
12
12
|
import { mutate } from 'array-move';
|
|
13
|
+
import { FeelersEditor } from 'feelers';
|
|
13
14
|
import FeelEditor from '@bpmn-io/feel-editor';
|
|
14
15
|
import Big from 'big.js';
|
|
15
16
|
|
|
@@ -569,19 +570,78 @@ class FormFieldRegistry extends FormFieldRegistry$1 {
|
|
|
569
570
|
}
|
|
570
571
|
}
|
|
571
572
|
|
|
573
|
+
class FormLayoutValidator {
|
|
574
|
+
/**
|
|
575
|
+
* @constructor
|
|
576
|
+
*
|
|
577
|
+
* @param { import('./FormLayouter').default } formLayouter
|
|
578
|
+
* @param { import('./FormFieldRegistry').default } formFieldRegistry
|
|
579
|
+
*/
|
|
580
|
+
constructor(formLayouter, formFieldRegistry) {
|
|
581
|
+
this._formLayouter = formLayouter;
|
|
582
|
+
this._formFieldRegistry = formFieldRegistry;
|
|
583
|
+
}
|
|
584
|
+
validateField(field = {}, columns, row) {
|
|
585
|
+
// allow empty (auto columns)
|
|
586
|
+
if (columns) {
|
|
587
|
+
// allow minimum 2 cols
|
|
588
|
+
if (columns < 2) {
|
|
589
|
+
return 'Minimum 2 columns are allowed';
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// allow maximum 16 cols
|
|
593
|
+
if (columns > 16) {
|
|
594
|
+
return 'Maximum 16 columns are allowed';
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (!row) {
|
|
598
|
+
row = this._formLayouter.getRowForField(field);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// calculate columns with and without updated field
|
|
602
|
+
let sumColumns = parseInt(columns) || 0;
|
|
603
|
+
let sumFields = 1;
|
|
604
|
+
let sumAutoCols = columns ? 0 : 1;
|
|
605
|
+
row.components.forEach(id => {
|
|
606
|
+
if (field.id === id) {
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
const component = this._formFieldRegistry.get(id);
|
|
610
|
+
const cols = (component.layout || {}).columns;
|
|
611
|
+
if (!cols) {
|
|
612
|
+
sumAutoCols++;
|
|
613
|
+
}
|
|
614
|
+
sumColumns += parseInt(cols) || 0;
|
|
615
|
+
sumFields++;
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// do not allow overflows
|
|
619
|
+
if (sumColumns > 16 || sumColumns === 16 && sumAutoCols > 0 || columns === 16 && sumFields > 1) {
|
|
620
|
+
return 'New value exceeds the maximum of 16 columns per row';
|
|
621
|
+
}
|
|
622
|
+
if (sumFields > 4) {
|
|
623
|
+
return 'Maximum 4 fields per row are allowed';
|
|
624
|
+
}
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
FormLayoutValidator.$inject = ['formLayouter', 'formFieldRegistry'];
|
|
629
|
+
|
|
572
630
|
class Importer {
|
|
573
631
|
/**
|
|
574
632
|
* @constructor
|
|
575
633
|
* @param { import('../core/FormFieldRegistry').default } formFieldRegistry
|
|
576
634
|
* @param { import('../core/FieldFactory').default } fieldFactory
|
|
635
|
+
* @param { import('../core/FormLayouter').default } formLayouter
|
|
577
636
|
*/
|
|
578
|
-
constructor(formFieldRegistry, fieldFactory) {
|
|
637
|
+
constructor(formFieldRegistry, fieldFactory, formLayouter) {
|
|
579
638
|
this._formFieldRegistry = formFieldRegistry;
|
|
580
639
|
this._fieldFactory = fieldFactory;
|
|
640
|
+
this._formLayouter = formLayouter;
|
|
581
641
|
}
|
|
582
642
|
|
|
583
643
|
/**
|
|
584
|
-
* Import schema creating fields, attaching additional
|
|
644
|
+
* Import schema creating rows, fields, attaching additional
|
|
585
645
|
* information to each field and adding fields to the
|
|
586
646
|
* field registry.
|
|
587
647
|
*
|
|
@@ -601,6 +661,7 @@ class Importer {
|
|
|
601
661
|
const warnings = [];
|
|
602
662
|
try {
|
|
603
663
|
const importedSchema = this.importFormField(clone(schema));
|
|
664
|
+
this._formLayouter.calculateLayout(clone(importedSchema));
|
|
604
665
|
return {
|
|
605
666
|
schema: importedSchema,
|
|
606
667
|
warnings
|
|
@@ -665,7 +726,7 @@ class Importer {
|
|
|
665
726
|
});
|
|
666
727
|
}
|
|
667
728
|
}
|
|
668
|
-
Importer.$inject = ['formFieldRegistry', 'fieldFactory'];
|
|
729
|
+
Importer.$inject = ['formFieldRegistry', 'fieldFactory', 'formLayouter'];
|
|
669
730
|
|
|
670
731
|
var importModule = {
|
|
671
732
|
importer: ['type', Importer]
|
|
@@ -682,11 +743,35 @@ function editorFormFieldClasses(type, {
|
|
|
682
743
|
});
|
|
683
744
|
}
|
|
684
745
|
|
|
685
|
-
|
|
746
|
+
const DragAndDropContext = createContext({
|
|
747
|
+
drake: null
|
|
748
|
+
});
|
|
749
|
+
var DragAndDropContext$1 = DragAndDropContext;
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* @param {string} type
|
|
753
|
+
* @param {boolean} [strict]
|
|
754
|
+
*
|
|
755
|
+
* @returns {any}
|
|
756
|
+
*/
|
|
757
|
+
function getService$1(type, strict) {}
|
|
758
|
+
const FormEditorContext = createContext({
|
|
759
|
+
getService: getService$1
|
|
760
|
+
});
|
|
761
|
+
var FormEditorContext$1 = FormEditorContext;
|
|
762
|
+
|
|
763
|
+
function useService$1 (type, strict) {
|
|
764
|
+
const {
|
|
765
|
+
getService
|
|
766
|
+
} = useContext(FormEditorContext$1);
|
|
767
|
+
return getService(type, strict);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function _extends$3() { _extends$3 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$3.apply(this, arguments); }
|
|
686
771
|
var CloseIcon = (({
|
|
687
772
|
styles = {},
|
|
688
773
|
...props
|
|
689
|
-
}) => /*#__PURE__*/React.createElement("svg", _extends$
|
|
774
|
+
}) => /*#__PURE__*/React.createElement("svg", _extends$3({
|
|
690
775
|
width: "16",
|
|
691
776
|
height: "16",
|
|
692
777
|
fill: "currentColor",
|
|
@@ -697,6 +782,23 @@ var CloseIcon = (({
|
|
|
697
782
|
d: "M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7z"
|
|
698
783
|
})));
|
|
699
784
|
|
|
785
|
+
function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$2.apply(this, arguments); }
|
|
786
|
+
var DraggableIcon = (({
|
|
787
|
+
styles = {},
|
|
788
|
+
...props
|
|
789
|
+
}) => /*#__PURE__*/React.createElement("svg", _extends$2({
|
|
790
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
791
|
+
width: "16",
|
|
792
|
+
height: "16",
|
|
793
|
+
fill: "currentcolor",
|
|
794
|
+
viewBox: "0 0 32 32"
|
|
795
|
+
}, props), /*#__PURE__*/React.createElement("path", {
|
|
796
|
+
d: "M10 6h4v4h-4zm8 0h4v4h-4zm-8 8h4v4h-4zm8 0h4v4h-4zm-8 8h4v4h-4zm8 0h4v4h-4z"
|
|
797
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
798
|
+
d: "M0 0h32v32H0z",
|
|
799
|
+
fill: "none"
|
|
800
|
+
})));
|
|
801
|
+
|
|
700
802
|
function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); }
|
|
701
803
|
var SearchIcon = (({
|
|
702
804
|
styles = {},
|
|
@@ -717,6 +819,8 @@ function EditorText(props) {
|
|
|
717
819
|
text = ''
|
|
718
820
|
} = props.field;
|
|
719
821
|
const Icon = iconsByType('text');
|
|
822
|
+
const templating = useService$1('templating');
|
|
823
|
+
const expressionLanguage = useService$1('expressionLanguage');
|
|
720
824
|
if (!text) {
|
|
721
825
|
return jsx("div", {
|
|
722
826
|
class: editorFormFieldClasses(type),
|
|
@@ -728,7 +832,7 @@ function EditorText(props) {
|
|
|
728
832
|
})
|
|
729
833
|
});
|
|
730
834
|
}
|
|
731
|
-
if (isExpression(text)) {
|
|
835
|
+
if (expressionLanguage.isExpression(text)) {
|
|
732
836
|
return jsx("div", {
|
|
733
837
|
class: editorFormFieldClasses(type),
|
|
734
838
|
children: jsxs("div", {
|
|
@@ -739,6 +843,17 @@ function EditorText(props) {
|
|
|
739
843
|
})
|
|
740
844
|
});
|
|
741
845
|
}
|
|
846
|
+
if (templating.isTemplate(text)) {
|
|
847
|
+
return jsx("div", {
|
|
848
|
+
class: editorFormFieldClasses(type),
|
|
849
|
+
children: jsxs("div", {
|
|
850
|
+
class: "fjs-form-field-placeholder",
|
|
851
|
+
children: [jsx(Icon, {
|
|
852
|
+
viewBox: "0 0 54 54"
|
|
853
|
+
}), "Text view is templated"]
|
|
854
|
+
})
|
|
855
|
+
});
|
|
856
|
+
}
|
|
742
857
|
return jsx(Text$1, {
|
|
743
858
|
...props,
|
|
744
859
|
disableLinks: true
|
|
@@ -759,30 +874,6 @@ class EditorFormFields extends FormFields {
|
|
|
759
874
|
}
|
|
760
875
|
}
|
|
761
876
|
|
|
762
|
-
const DragAndDropContext = createContext({
|
|
763
|
-
drake: null
|
|
764
|
-
});
|
|
765
|
-
var DragAndDropContext$1 = DragAndDropContext;
|
|
766
|
-
|
|
767
|
-
/**
|
|
768
|
-
* @param {string} type
|
|
769
|
-
* @param {boolean} [strict]
|
|
770
|
-
*
|
|
771
|
-
* @returns {any}
|
|
772
|
-
*/
|
|
773
|
-
function getService$1(type, strict) {}
|
|
774
|
-
const FormEditorContext = createContext({
|
|
775
|
-
getService: getService$1
|
|
776
|
-
});
|
|
777
|
-
var FormEditorContext$1 = FormEditorContext;
|
|
778
|
-
|
|
779
|
-
function useService$1 (type, strict) {
|
|
780
|
-
const {
|
|
781
|
-
getService
|
|
782
|
-
} = useContext(FormEditorContext$1);
|
|
783
|
-
return getService(type, strict);
|
|
784
|
-
}
|
|
785
|
-
|
|
786
877
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
787
878
|
var ListDeleteIcon = (({
|
|
788
879
|
styles = {},
|
|
@@ -944,6 +1035,307 @@ function unset() {
|
|
|
944
1035
|
set(null);
|
|
945
1036
|
}
|
|
946
1037
|
|
|
1038
|
+
const DRAG_CONTAINER_CLS = 'fjs-drag-container';
|
|
1039
|
+
const DROP_CONTAINER_VERTICAL_CLS = 'fjs-drop-container-vertical';
|
|
1040
|
+
const DROP_CONTAINER_HORIZONTAL_CLS = 'fjs-drop-container-horizontal';
|
|
1041
|
+
const DRAG_MOVE_CLS = 'fjs-drag-move';
|
|
1042
|
+
const DRAG_ROW_MOVE_CLS = 'fjs-drag-row-move';
|
|
1043
|
+
const DRAG_COPY_CLS = 'fjs-drag-copy';
|
|
1044
|
+
const DRAG_NO_DROP_CLS = 'fjs-no-drop';
|
|
1045
|
+
const DRAG_NO_MOVE_CLS = 'fjs-no-move';
|
|
1046
|
+
const ERROR_DROP_CLS = 'fjs-error-drop';
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* @typedef { { id: String, components: Array<any> } } FormRow
|
|
1050
|
+
*/
|
|
1051
|
+
|
|
1052
|
+
class Dragging {
|
|
1053
|
+
/**
|
|
1054
|
+
* @constructor
|
|
1055
|
+
*
|
|
1056
|
+
* @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
|
|
1057
|
+
* @param { import('../../core/FormLayouter').default } formLayouter
|
|
1058
|
+
* @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
|
|
1059
|
+
* @param { import('../../core/EventBus').default } eventBus
|
|
1060
|
+
* @param { import('../modeling/Modeling').default } modeling
|
|
1061
|
+
*/
|
|
1062
|
+
constructor(formFieldRegistry, formLayouter, formLayoutValidator, eventBus, modeling) {
|
|
1063
|
+
this._formFieldRegistry = formFieldRegistry;
|
|
1064
|
+
this._formLayouter = formLayouter;
|
|
1065
|
+
this._formLayoutValidator = formLayoutValidator;
|
|
1066
|
+
this._eventBus = eventBus;
|
|
1067
|
+
this._modeling = modeling;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* Calculcates position in form schema given the dropped place.
|
|
1072
|
+
*
|
|
1073
|
+
* @param { FormRow } targetRow
|
|
1074
|
+
* @param { any } targetFormField
|
|
1075
|
+
* @param { HTMLElement } sibling
|
|
1076
|
+
* @returns { number }
|
|
1077
|
+
*/
|
|
1078
|
+
getTargetIndex(targetRow, targetFormField, sibling) {
|
|
1079
|
+
/** @type HTMLElement */
|
|
1080
|
+
const siblingFormFieldNode = sibling && sibling.querySelector('.fjs-element');
|
|
1081
|
+
const siblingFormField = siblingFormFieldNode && this._formFieldRegistry.get(siblingFormFieldNode.dataset.id);
|
|
1082
|
+
|
|
1083
|
+
// (1) dropped before existing field => place before
|
|
1084
|
+
if (siblingFormField) {
|
|
1085
|
+
return getFormFieldIndex$1(targetFormField, siblingFormField);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// (2) dropped in row => place at the end of row (after last field in row)
|
|
1089
|
+
if (targetRow) {
|
|
1090
|
+
return getFormFieldIndex$1(targetFormField, this._formFieldRegistry.get(targetRow.components[targetRow.components.length - 1])) + 1;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// (3) dropped as last item
|
|
1094
|
+
return targetFormField.components.length;
|
|
1095
|
+
}
|
|
1096
|
+
validateDrop(element, target) {
|
|
1097
|
+
const formFieldNode = element.querySelector('.fjs-element');
|
|
1098
|
+
const targetRow = this._formLayouter.getRow(target.dataset.rowId);
|
|
1099
|
+
let columns;
|
|
1100
|
+
let formField;
|
|
1101
|
+
if (formFieldNode) {
|
|
1102
|
+
formField = this._formFieldRegistry.get(formFieldNode.dataset.id);
|
|
1103
|
+
columns = (formField.layout || {}).columns;
|
|
1104
|
+
}
|
|
1105
|
+
return this._formLayoutValidator.validateField(formField, columns, targetRow);
|
|
1106
|
+
}
|
|
1107
|
+
moveField(element, source, targetRow, targetFormField, targetIndex) {
|
|
1108
|
+
const formFieldNode = element.querySelector('.fjs-element');
|
|
1109
|
+
const formField = this._formFieldRegistry.get(formFieldNode.dataset.id);
|
|
1110
|
+
const sourceParent = getFormParent(source);
|
|
1111
|
+
const sourceFormField = this._formFieldRegistry.get(sourceParent.dataset.id);
|
|
1112
|
+
const sourceIndex = getFormFieldIndex$1(sourceFormField, formField);
|
|
1113
|
+
const sourceRow = this._formLayouter.getRowForField(formField);
|
|
1114
|
+
this._modeling.moveFormField(formField, sourceFormField, targetFormField, sourceIndex, targetIndex, sourceRow, targetRow);
|
|
1115
|
+
}
|
|
1116
|
+
createNewField(element, targetRow, targetFormField, targetIndex) {
|
|
1117
|
+
const type = element.dataset.fieldType;
|
|
1118
|
+
let attrs = {
|
|
1119
|
+
type
|
|
1120
|
+
};
|
|
1121
|
+
attrs = {
|
|
1122
|
+
...attrs,
|
|
1123
|
+
layout: {
|
|
1124
|
+
row: targetRow ? targetRow.id : this._formLayouter.nextRowId(),
|
|
1125
|
+
// enable auto columns
|
|
1126
|
+
columns: null
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
this._modeling.addFormField(attrs, targetFormField, targetIndex);
|
|
1130
|
+
}
|
|
1131
|
+
handleRowDrop(el, target, source, sibling) {
|
|
1132
|
+
const targetFormField = this._formFieldRegistry.get(target.dataset.id);
|
|
1133
|
+
const rowNode = el.querySelector('.fjs-layout-row');
|
|
1134
|
+
const row = this._formLayouter.getRow(rowNode.dataset.rowId);
|
|
1135
|
+
|
|
1136
|
+
// move each field in the row before first field of sibling row
|
|
1137
|
+
row.components.forEach((id, index) => {
|
|
1138
|
+
const formField = this._formFieldRegistry.get(id);
|
|
1139
|
+
const sourceParent = getFormParent(source);
|
|
1140
|
+
const sourceFormField = this._formFieldRegistry.get(sourceParent.dataset.id);
|
|
1141
|
+
const siblingRowNode = sibling && sibling.querySelector('.fjs-layout-row');
|
|
1142
|
+
const siblingRow = siblingRowNode && this._formLayouter.getRow(siblingRowNode.dataset.rowId);
|
|
1143
|
+
const siblingFormField = sibling && this._formFieldRegistry.get(siblingRow.components[0]);
|
|
1144
|
+
const sourceIndex = getFormFieldIndex$1(sourceFormField, formField);
|
|
1145
|
+
const targetIndex = (siblingRowNode ? getFormFieldIndex$1(targetFormField, siblingFormField) : targetFormField.components.length) + index;
|
|
1146
|
+
this._modeling.moveFormField(formField, sourceFormField, targetFormField, sourceIndex, targetIndex, row, row);
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
handleElementDrop(el, target, source, sibling, drake) {
|
|
1150
|
+
// (1) detect drop target
|
|
1151
|
+
const targetFormField = this._formFieldRegistry.get(getFormParent(target).dataset.id);
|
|
1152
|
+
let targetRow;
|
|
1153
|
+
|
|
1154
|
+
// (2.1) dropped in existing row
|
|
1155
|
+
if (isRow(target)) {
|
|
1156
|
+
unsetDropNotAllowed(target);
|
|
1157
|
+
targetRow = this._formLayouter.getRow(target.dataset.rowId);
|
|
1158
|
+
|
|
1159
|
+
// validate whether drop is allowed
|
|
1160
|
+
const validationError = this.validateDrop(el, target);
|
|
1161
|
+
if (validationError) {
|
|
1162
|
+
return drake.cancel(true);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
drake.remove();
|
|
1166
|
+
|
|
1167
|
+
// (3) detect position to drop field in schema order
|
|
1168
|
+
const targetIndex = this.getTargetIndex(targetRow, targetFormField, sibling);
|
|
1169
|
+
|
|
1170
|
+
// (4) create new field or move existing
|
|
1171
|
+
if (isPalette(source)) {
|
|
1172
|
+
this.createNewField(el, targetRow, targetFormField, targetIndex);
|
|
1173
|
+
} else {
|
|
1174
|
+
this.moveField(el, source, targetRow, targetFormField, targetIndex);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
|
|
1180
|
+
*/
|
|
1181
|
+
createDragulaInstance(options) {
|
|
1182
|
+
const {
|
|
1183
|
+
container,
|
|
1184
|
+
direction,
|
|
1185
|
+
mirrorContainer
|
|
1186
|
+
} = options || {};
|
|
1187
|
+
const dragulaInstance = dragula({
|
|
1188
|
+
direction,
|
|
1189
|
+
mirrorContainer,
|
|
1190
|
+
isContainer(el) {
|
|
1191
|
+
return container.some(cls => el.classList.contains(cls));
|
|
1192
|
+
},
|
|
1193
|
+
moves(el, source, handle) {
|
|
1194
|
+
return !handle.classList.contains(DRAG_NO_MOVE_CLS) && (el.classList.contains(DRAG_MOVE_CLS) || el.classList.contains(DRAG_COPY_CLS) || el.classList.contains(DRAG_ROW_MOVE_CLS));
|
|
1195
|
+
},
|
|
1196
|
+
copy(el) {
|
|
1197
|
+
return el.classList.contains(DRAG_COPY_CLS);
|
|
1198
|
+
},
|
|
1199
|
+
accepts: (el, target) => {
|
|
1200
|
+
unsetDropNotAllowed(target);
|
|
1201
|
+
|
|
1202
|
+
// allow dropping rows only between rows
|
|
1203
|
+
if (el.classList.contains(DRAG_ROW_MOVE_CLS)) {
|
|
1204
|
+
return !target.classList.contains(DROP_CONTAINER_HORIZONTAL_CLS);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// validate field drop in row
|
|
1208
|
+
if (isRow(target)) {
|
|
1209
|
+
const validationError = this.validateDrop(el, target);
|
|
1210
|
+
if (validationError) {
|
|
1211
|
+
// set error feedback to row
|
|
1212
|
+
setDropNotAllowed(target);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return !target.classList.contains(DRAG_NO_DROP_CLS);
|
|
1216
|
+
},
|
|
1217
|
+
slideFactorX: 10,
|
|
1218
|
+
slideFactorY: 5
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1221
|
+
// bind life cycle events
|
|
1222
|
+
dragulaInstance.on('drag', (element, source) => {
|
|
1223
|
+
this.emit('drag.start', {
|
|
1224
|
+
element,
|
|
1225
|
+
source
|
|
1226
|
+
});
|
|
1227
|
+
});
|
|
1228
|
+
dragulaInstance.on('dragend', element => {
|
|
1229
|
+
this.emit('drag.end', {
|
|
1230
|
+
element
|
|
1231
|
+
});
|
|
1232
|
+
});
|
|
1233
|
+
dragulaInstance.on('drop', (element, target, source, sibling) => {
|
|
1234
|
+
this.emit('drag.drop', {
|
|
1235
|
+
element,
|
|
1236
|
+
target,
|
|
1237
|
+
source,
|
|
1238
|
+
sibling
|
|
1239
|
+
});
|
|
1240
|
+
});
|
|
1241
|
+
dragulaInstance.on('over', (element, container, source) => {
|
|
1242
|
+
this.emit('drag.hover', {
|
|
1243
|
+
element,
|
|
1244
|
+
container,
|
|
1245
|
+
source
|
|
1246
|
+
});
|
|
1247
|
+
});
|
|
1248
|
+
dragulaInstance.on('out', (element, container, source) => {
|
|
1249
|
+
this.emit('drag.out', {
|
|
1250
|
+
element,
|
|
1251
|
+
container,
|
|
1252
|
+
source
|
|
1253
|
+
});
|
|
1254
|
+
});
|
|
1255
|
+
dragulaInstance.on('cancel', (element, container, source) => {
|
|
1256
|
+
this.emit('drag.cancel', {
|
|
1257
|
+
element,
|
|
1258
|
+
container,
|
|
1259
|
+
source
|
|
1260
|
+
});
|
|
1261
|
+
});
|
|
1262
|
+
dragulaInstance.on('drop', (el, target, source, sibling) => {
|
|
1263
|
+
if (!target) {
|
|
1264
|
+
dragulaInstance.remove();
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// (1) handle row drop
|
|
1269
|
+
if (isDragRow(el)) {
|
|
1270
|
+
this.handleRowDrop(el, target, source, sibling);
|
|
1271
|
+
} else {
|
|
1272
|
+
// (2) handle form field drop
|
|
1273
|
+
this.handleElementDrop(el, target, source, sibling, dragulaInstance);
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
this.emit('dragula.created', dragulaInstance);
|
|
1277
|
+
return dragulaInstance;
|
|
1278
|
+
}
|
|
1279
|
+
emit(event, context) {
|
|
1280
|
+
this._eventBus.fire(event, context);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
Dragging.$inject = ['formFieldRegistry', 'formLayouter', 'formLayoutValidator', 'eventBus', 'modeling'];
|
|
1284
|
+
|
|
1285
|
+
// helper //////////
|
|
1286
|
+
|
|
1287
|
+
function getFormFieldIndex$1(parent, formField) {
|
|
1288
|
+
let fieldFormIndex = parent.components.length;
|
|
1289
|
+
parent.components.forEach(({
|
|
1290
|
+
id
|
|
1291
|
+
}, index) => {
|
|
1292
|
+
if (id === formField.id) {
|
|
1293
|
+
fieldFormIndex = index;
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1296
|
+
return fieldFormIndex;
|
|
1297
|
+
}
|
|
1298
|
+
function isRow(node) {
|
|
1299
|
+
return node.classList.contains('fjs-layout-row');
|
|
1300
|
+
}
|
|
1301
|
+
function isDragRow(node) {
|
|
1302
|
+
return node.classList.contains(DRAG_ROW_MOVE_CLS);
|
|
1303
|
+
}
|
|
1304
|
+
function isPalette(node) {
|
|
1305
|
+
return node.classList.contains('fjs-palette-fields');
|
|
1306
|
+
}
|
|
1307
|
+
function getFormParent(node) {
|
|
1308
|
+
return node.closest('.fjs-element');
|
|
1309
|
+
}
|
|
1310
|
+
function setDropNotAllowed(node) {
|
|
1311
|
+
node.classList.add(ERROR_DROP_CLS);
|
|
1312
|
+
set('not-allowed');
|
|
1313
|
+
}
|
|
1314
|
+
function unsetDropNotAllowed(node) {
|
|
1315
|
+
node.classList.remove(ERROR_DROP_CLS);
|
|
1316
|
+
set('grabbing');
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
function FieldDragPreview(props) {
|
|
1320
|
+
const {
|
|
1321
|
+
class: className,
|
|
1322
|
+
Icon,
|
|
1323
|
+
label
|
|
1324
|
+
} = props;
|
|
1325
|
+
return jsxs("div", {
|
|
1326
|
+
class: classnames('fjs-field-preview', className),
|
|
1327
|
+
children: [jsx(Icon, {
|
|
1328
|
+
class: "fjs-field-preview-icon",
|
|
1329
|
+
width: "36",
|
|
1330
|
+
height: "36",
|
|
1331
|
+
viewBox: "0 0 54 54"
|
|
1332
|
+
}), jsx("span", {
|
|
1333
|
+
class: "fjs-field-preview-text",
|
|
1334
|
+
children: label
|
|
1335
|
+
})]
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
|
|
947
1339
|
function ContextPad(props) {
|
|
948
1340
|
if (!props.children) {
|
|
949
1341
|
return null;
|
|
@@ -990,7 +1382,7 @@ function Element(props) {
|
|
|
990
1382
|
event.stopPropagation();
|
|
991
1383
|
selection.toggle(field);
|
|
992
1384
|
}
|
|
993
|
-
const classes = [
|
|
1385
|
+
const classes = [];
|
|
994
1386
|
if (props.class) {
|
|
995
1387
|
classes.push(...props.class.split(' '));
|
|
996
1388
|
}
|
|
@@ -1009,7 +1401,9 @@ function Element(props) {
|
|
|
1009
1401
|
"data-field-type": type,
|
|
1010
1402
|
onClick: onClick,
|
|
1011
1403
|
ref: ref,
|
|
1012
|
-
children: [jsx(
|
|
1404
|
+
children: [jsx(DebugColumns, {
|
|
1405
|
+
field: field
|
|
1406
|
+
}), jsx(ContextPad, {
|
|
1013
1407
|
children: selection.isSelected(field) && field.type !== 'default' ? jsx("button", {
|
|
1014
1408
|
class: "fjs-context-pad-item",
|
|
1015
1409
|
onClick: onRemove,
|
|
@@ -1018,6 +1412,20 @@ function Element(props) {
|
|
|
1018
1412
|
}), props.children]
|
|
1019
1413
|
});
|
|
1020
1414
|
}
|
|
1415
|
+
function DebugColumns(props) {
|
|
1416
|
+
const {
|
|
1417
|
+
field
|
|
1418
|
+
} = props;
|
|
1419
|
+
const debugColumnsConfig = useService$1('config.debugColumns');
|
|
1420
|
+
if (!debugColumnsConfig || field.type == 'default') {
|
|
1421
|
+
return null;
|
|
1422
|
+
}
|
|
1423
|
+
return jsx("div", {
|
|
1424
|
+
style: "width: fit-content; padding: 2px 6px; height: 16px; background: var(--color-blue-205-100-95); display: flex; justify-content: center; align-items: center; position: absolute; bottom: -2px; z-index: 2; font-size: 10px; right: 3px;",
|
|
1425
|
+
class: "fjs-debug-columns",
|
|
1426
|
+
children: (field.layout || {}).columns || 'auto'
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1021
1429
|
function Children(props) {
|
|
1022
1430
|
const {
|
|
1023
1431
|
field
|
|
@@ -1025,7 +1433,7 @@ function Children(props) {
|
|
|
1025
1433
|
const {
|
|
1026
1434
|
id
|
|
1027
1435
|
} = field;
|
|
1028
|
-
const classes = ['fjs-children',
|
|
1436
|
+
const classes = ['fjs-children', DROP_CONTAINER_VERTICAL_CLS];
|
|
1029
1437
|
if (props.class) {
|
|
1030
1438
|
classes.push(...props.class.split(' '));
|
|
1031
1439
|
}
|
|
@@ -1035,12 +1443,51 @@ function Children(props) {
|
|
|
1035
1443
|
children: props.children
|
|
1036
1444
|
});
|
|
1037
1445
|
}
|
|
1446
|
+
function Row(props) {
|
|
1447
|
+
const {
|
|
1448
|
+
row
|
|
1449
|
+
} = props;
|
|
1450
|
+
const {
|
|
1451
|
+
id
|
|
1452
|
+
} = row;
|
|
1453
|
+
const classes = [DROP_CONTAINER_HORIZONTAL_CLS];
|
|
1454
|
+
if (props.class) {
|
|
1455
|
+
classes.push(...props.class.split(' '));
|
|
1456
|
+
}
|
|
1457
|
+
return jsxs("div", {
|
|
1458
|
+
class: classnames(DRAG_ROW_MOVE_CLS),
|
|
1459
|
+
children: [jsx("span", {
|
|
1460
|
+
class: "fjs-row-dragger",
|
|
1461
|
+
children: jsx(DraggableIcon, {})
|
|
1462
|
+
}), jsx("div", {
|
|
1463
|
+
class: classes.join(' '),
|
|
1464
|
+
"data-row-id": id,
|
|
1465
|
+
children: props.children
|
|
1466
|
+
})]
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
function Column(props) {
|
|
1470
|
+
const {
|
|
1471
|
+
field
|
|
1472
|
+
} = props;
|
|
1473
|
+
const classes = [DRAG_MOVE_CLS];
|
|
1474
|
+
if (field.type === 'default') {
|
|
1475
|
+
return props.children;
|
|
1476
|
+
}
|
|
1477
|
+
if (props.class) {
|
|
1478
|
+
classes.push(...props.class.split(' '));
|
|
1479
|
+
}
|
|
1480
|
+
return jsx("div", {
|
|
1481
|
+
"data-field-type": field.type,
|
|
1482
|
+
class: classes.join(' '),
|
|
1483
|
+
children: props.children
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1038
1486
|
function FormEditor$1(props) {
|
|
1039
|
-
const
|
|
1487
|
+
const dragging = useService$1('dragging'),
|
|
1488
|
+
eventBus = useService$1('eventBus'),
|
|
1040
1489
|
formEditor = useService$1('formEditor'),
|
|
1041
|
-
formFieldRegistry = useService$1('formFieldRegistry'),
|
|
1042
1490
|
injector = useService$1('injector'),
|
|
1043
|
-
modeling = useService$1('modeling'),
|
|
1044
1491
|
selection = useService$1('selection'),
|
|
1045
1492
|
palette = useService$1('palette'),
|
|
1046
1493
|
paletteConfig = useService$1('config.palette'),
|
|
@@ -1049,6 +1496,7 @@ function FormEditor$1(props) {
|
|
|
1049
1496
|
const {
|
|
1050
1497
|
schema
|
|
1051
1498
|
} = formEditor._getState();
|
|
1499
|
+
const formContainerRef = useRef(null);
|
|
1052
1500
|
const paletteRef = useRef(null);
|
|
1053
1501
|
const propertiesPanelRef = useRef(null);
|
|
1054
1502
|
const [, setSelection] = useState(schema);
|
|
@@ -1067,98 +1515,12 @@ function FormEditor$1(props) {
|
|
|
1067
1515
|
drake
|
|
1068
1516
|
};
|
|
1069
1517
|
useEffect(() => {
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
return el.classList.contains('fjs-drag-container');
|
|
1077
|
-
},
|
|
1078
|
-
copy(el) {
|
|
1079
|
-
return el.classList.contains('fjs-drag-copy');
|
|
1080
|
-
},
|
|
1081
|
-
accepts(el, target) {
|
|
1082
|
-
return !target.classList.contains('fjs-no-drop');
|
|
1083
|
-
},
|
|
1084
|
-
slideFactorX: 10,
|
|
1085
|
-
slideFactorY: 5
|
|
1086
|
-
});
|
|
1087
|
-
|
|
1088
|
-
// bind life cycle events
|
|
1089
|
-
dragulaInstance.on('drag', (element, source) => {
|
|
1090
|
-
handleDragEvent('drag.start', {
|
|
1091
|
-
element,
|
|
1092
|
-
source
|
|
1093
|
-
});
|
|
1094
|
-
});
|
|
1095
|
-
dragulaInstance.on('dragend', element => {
|
|
1096
|
-
handleDragEvent('drag.end', {
|
|
1097
|
-
element
|
|
1098
|
-
});
|
|
1099
|
-
});
|
|
1100
|
-
dragulaInstance.on('drop', (element, target, source, sibling) => {
|
|
1101
|
-
handleDragEvent('drag.drop', {
|
|
1102
|
-
element,
|
|
1103
|
-
target,
|
|
1104
|
-
source,
|
|
1105
|
-
sibling
|
|
1106
|
-
});
|
|
1107
|
-
});
|
|
1108
|
-
dragulaInstance.on('over', (element, container, source) => {
|
|
1109
|
-
handleDragEvent('drag.hover', {
|
|
1110
|
-
element,
|
|
1111
|
-
container,
|
|
1112
|
-
source
|
|
1113
|
-
});
|
|
1114
|
-
});
|
|
1115
|
-
dragulaInstance.on('out', (element, container, source) => {
|
|
1116
|
-
handleDragEvent('drag.out', {
|
|
1117
|
-
element,
|
|
1118
|
-
container,
|
|
1119
|
-
source
|
|
1120
|
-
});
|
|
1121
|
-
});
|
|
1122
|
-
dragulaInstance.on('cancel', (element, container, source) => {
|
|
1123
|
-
handleDragEvent('drag.cancel', {
|
|
1124
|
-
element,
|
|
1125
|
-
container,
|
|
1126
|
-
source
|
|
1127
|
-
});
|
|
1128
|
-
});
|
|
1129
|
-
|
|
1130
|
-
// set custom styling
|
|
1131
|
-
dragulaInstance.on('drag', () => {
|
|
1132
|
-
set('grabbing');
|
|
1133
|
-
});
|
|
1134
|
-
dragulaInstance.on('dragend', () => {
|
|
1135
|
-
unset();
|
|
1136
|
-
});
|
|
1137
|
-
dragulaInstance.on('drop', (el, target, source, sibling) => {
|
|
1138
|
-
dragulaInstance.remove();
|
|
1139
|
-
if (!target) {
|
|
1140
|
-
return;
|
|
1141
|
-
}
|
|
1142
|
-
const targetFormField = formFieldRegistry.get(target.dataset.id);
|
|
1143
|
-
const siblingFormField = sibling && formFieldRegistry.get(sibling.dataset.id),
|
|
1144
|
-
targetIndex = siblingFormField ? getFormFieldIndex(targetFormField, siblingFormField) : targetFormField.components.length;
|
|
1145
|
-
if (source.classList.contains('fjs-palette-fields')) {
|
|
1146
|
-
const type = el.dataset.fieldType;
|
|
1147
|
-
modeling.addFormField({
|
|
1148
|
-
type
|
|
1149
|
-
}, targetFormField, targetIndex);
|
|
1150
|
-
} else {
|
|
1151
|
-
const formField = formFieldRegistry.get(el.dataset.id),
|
|
1152
|
-
sourceFormField = formFieldRegistry.get(source.dataset.id),
|
|
1153
|
-
sourceIndex = getFormFieldIndex(sourceFormField, formField);
|
|
1154
|
-
modeling.moveFormField(formField, sourceFormField, targetFormField, sourceIndex, targetIndex);
|
|
1155
|
-
}
|
|
1156
|
-
});
|
|
1157
|
-
eventBus.fire('dragula.created');
|
|
1158
|
-
setDrake(dragulaInstance);
|
|
1159
|
-
return dragulaInstance;
|
|
1160
|
-
};
|
|
1161
|
-
let dragulaInstance = createDragulaInstance();
|
|
1518
|
+
let dragulaInstance = dragging.createDragulaInstance({
|
|
1519
|
+
container: [DRAG_CONTAINER_CLS, DROP_CONTAINER_VERTICAL_CLS, DROP_CONTAINER_HORIZONTAL_CLS],
|
|
1520
|
+
direction: 'vertical',
|
|
1521
|
+
mirrorContainer: formContainerRef.current
|
|
1522
|
+
});
|
|
1523
|
+
setDrake(dragulaInstance);
|
|
1162
1524
|
const onDetach = () => {
|
|
1163
1525
|
if (dragulaInstance) {
|
|
1164
1526
|
dragulaInstance.destroy();
|
|
@@ -1167,14 +1529,34 @@ function FormEditor$1(props) {
|
|
|
1167
1529
|
};
|
|
1168
1530
|
const onAttach = () => {
|
|
1169
1531
|
onDetach();
|
|
1170
|
-
dragulaInstance = createDragulaInstance(
|
|
1532
|
+
dragulaInstance = dragging.createDragulaInstance({
|
|
1533
|
+
container: [DRAG_CONTAINER_CLS, DROP_CONTAINER_VERTICAL_CLS, DROP_CONTAINER_HORIZONTAL_CLS],
|
|
1534
|
+
direction: 'vertical',
|
|
1535
|
+
mirrorContainer: formContainerRef.current
|
|
1536
|
+
});
|
|
1537
|
+
setDrake(dragulaInstance);
|
|
1538
|
+
};
|
|
1539
|
+
const onCreate = drake => {
|
|
1540
|
+
setDrake(drake);
|
|
1541
|
+
};
|
|
1542
|
+
const onDragStart = () => {
|
|
1543
|
+
set('grabbing');
|
|
1544
|
+
};
|
|
1545
|
+
const onDragEnd = () => {
|
|
1546
|
+
unset();
|
|
1171
1547
|
};
|
|
1172
1548
|
eventBus.on('attach', onAttach);
|
|
1173
1549
|
eventBus.on('detach', onDetach);
|
|
1550
|
+
eventBus.on('dragula.created', onCreate);
|
|
1551
|
+
eventBus.on('drag.start', onDragStart);
|
|
1552
|
+
eventBus.on('drag.end', onDragEnd);
|
|
1174
1553
|
return () => {
|
|
1175
1554
|
onDetach();
|
|
1176
1555
|
eventBus.off('attach', onAttach);
|
|
1177
1556
|
eventBus.off('detach', onDetach);
|
|
1557
|
+
eventBus.off('dragula.created', onCreate);
|
|
1558
|
+
eventBus.off('drag.start', onDragStart);
|
|
1559
|
+
eventBus.off('drag.end', onDragEnd);
|
|
1178
1560
|
};
|
|
1179
1561
|
}, []);
|
|
1180
1562
|
|
|
@@ -1184,8 +1566,10 @@ function FormEditor$1(props) {
|
|
|
1184
1566
|
}, []);
|
|
1185
1567
|
const formRenderContext = {
|
|
1186
1568
|
Children,
|
|
1569
|
+
Column,
|
|
1187
1570
|
Element,
|
|
1188
|
-
Empty
|
|
1571
|
+
Empty,
|
|
1572
|
+
Row
|
|
1189
1573
|
};
|
|
1190
1574
|
const formContext = {
|
|
1191
1575
|
getService(type, strict = true) {
|
|
@@ -1234,6 +1618,7 @@ function FormEditor$1(props) {
|
|
|
1234
1618
|
class: "fjs-editor-palette-container",
|
|
1235
1619
|
ref: paletteRef
|
|
1236
1620
|
}), jsx("div", {
|
|
1621
|
+
ref: formContainerRef,
|
|
1237
1622
|
class: "fjs-form-container",
|
|
1238
1623
|
children: jsx(FormContext.Provider, {
|
|
1239
1624
|
value: formContext,
|
|
@@ -1269,29 +1654,39 @@ function CreatePreview(props) {
|
|
|
1269
1654
|
} = useContext(DragAndDropContext$1);
|
|
1270
1655
|
function handleCloned(clone, original, type) {
|
|
1271
1656
|
const fieldType = clone.dataset.fieldType;
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
label
|
|
1275
|
-
} = findPaletteEntry(fieldType);
|
|
1657
|
+
|
|
1658
|
+
// (1) field preview
|
|
1276
1659
|
if (fieldType) {
|
|
1660
|
+
const {
|
|
1661
|
+
label
|
|
1662
|
+
} = findPaletteEntry(fieldType);
|
|
1663
|
+
const Icon = iconsByType(fieldType);
|
|
1277
1664
|
clone.innerHTML = '';
|
|
1278
1665
|
clone.class = 'gu-mirror';
|
|
1666
|
+
clone.classList.add('fjs-field-preview-container');
|
|
1279
1667
|
if (original.classList.contains('fjs-palette-field')) {
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
children: [jsx(Icon, {
|
|
1283
|
-
class: "fjs-palette-field-icon",
|
|
1284
|
-
width: "36",
|
|
1285
|
-
height: "36",
|
|
1286
|
-
viewBox: "0 0 54 54"
|
|
1287
|
-
}), jsx("span", {
|
|
1288
|
-
class: "fjs-palette-field-text",
|
|
1289
|
-
children: label
|
|
1290
|
-
})]
|
|
1291
|
-
}), clone);
|
|
1292
|
-
} else {
|
|
1293
|
-
render(jsx(Icon, {}), clone);
|
|
1668
|
+
// default to auto columns when creating from palette
|
|
1669
|
+
clone.classList.add('cds--col');
|
|
1294
1670
|
}
|
|
1671
|
+
|
|
1672
|
+
// todo(pinussilvestrus): dragula, how to mitigate cursor position
|
|
1673
|
+
// https://github.com/bevacqua/dragula/issues/285
|
|
1674
|
+
render(jsx(FieldDragPreview, {
|
|
1675
|
+
label: label,
|
|
1676
|
+
Icon: Icon
|
|
1677
|
+
}), clone);
|
|
1678
|
+
} else {
|
|
1679
|
+
// (2) row preview
|
|
1680
|
+
|
|
1681
|
+
// remove elements from copy (context pad, row dragger, ...)
|
|
1682
|
+
['fjs-context-pad', 'fjs-row-dragger', 'fjs-debug-columns'].forEach(cls => {
|
|
1683
|
+
const cloneNode = clone.querySelectorAll('.' + cls);
|
|
1684
|
+
cloneNode.length && cloneNode.forEach(e => e.remove());
|
|
1685
|
+
});
|
|
1686
|
+
|
|
1687
|
+
// mirror grid
|
|
1688
|
+
clone.classList.add('cds--grid');
|
|
1689
|
+
clone.classList.add('cds--grid--condensed');
|
|
1295
1690
|
}
|
|
1296
1691
|
}
|
|
1297
1692
|
useEffect(() => {
|
|
@@ -1364,10 +1759,12 @@ var renderModule = {
|
|
|
1364
1759
|
|
|
1365
1760
|
var core = {
|
|
1366
1761
|
__depends__: [importModule, renderModule],
|
|
1762
|
+
debounce: ['factory', DebounceFactory],
|
|
1367
1763
|
eventBus: ['type', EventBus],
|
|
1368
1764
|
formFieldRegistry: ['type', FormFieldRegistry],
|
|
1369
|
-
|
|
1370
|
-
|
|
1765
|
+
formLayouter: ['type', FormLayouter],
|
|
1766
|
+
formLayoutValidator: ['type', FormLayoutValidator],
|
|
1767
|
+
fieldFactory: ['type', FieldFactory]
|
|
1371
1768
|
};
|
|
1372
1769
|
|
|
1373
1770
|
var NOT_REGISTERED_ERROR = 'is not a registered action',
|
|
@@ -1645,6 +2042,11 @@ var EditorActionsModule = {
|
|
|
1645
2042
|
editorActions: ['type', FormEditorActions]
|
|
1646
2043
|
};
|
|
1647
2044
|
|
|
2045
|
+
var DraggingModule = {
|
|
2046
|
+
__init__: ['dragging'],
|
|
2047
|
+
dragging: ['type', Dragging]
|
|
2048
|
+
};
|
|
2049
|
+
|
|
1648
2050
|
var KEYS_COPY = ['c', 'C', 'KeyC'];
|
|
1649
2051
|
var KEYS_PASTE = ['v', 'V', 'KeyV'];
|
|
1650
2052
|
var KEYS_REDO$1 = ['y', 'Y', 'KeyY'];
|
|
@@ -2057,6 +2459,13 @@ function updatePath(formFieldRegistry, formField, index) {
|
|
|
2057
2459
|
formField._path = [...parent._path, 'components', index];
|
|
2058
2460
|
return formField;
|
|
2059
2461
|
}
|
|
2462
|
+
function updateRow(formField, rowId) {
|
|
2463
|
+
formField.layout = {
|
|
2464
|
+
...(formField.layout || {}),
|
|
2465
|
+
row: rowId
|
|
2466
|
+
};
|
|
2467
|
+
return formField;
|
|
2468
|
+
}
|
|
2060
2469
|
|
|
2061
2470
|
class AddFormFieldHandler {
|
|
2062
2471
|
/**
|
|
@@ -2206,13 +2615,17 @@ class MoveFormFieldHandler {
|
|
|
2206
2615
|
sourceFormField,
|
|
2207
2616
|
targetFormField,
|
|
2208
2617
|
sourceIndex,
|
|
2209
|
-
targetIndex
|
|
2618
|
+
targetIndex,
|
|
2619
|
+
sourceRow,
|
|
2620
|
+
targetRow
|
|
2210
2621
|
} = context;
|
|
2211
2622
|
this.moveFormField({
|
|
2212
2623
|
sourceFormField: targetFormField,
|
|
2213
2624
|
targetFormField: sourceFormField,
|
|
2214
2625
|
sourceIndex: targetIndex,
|
|
2215
|
-
targetIndex: sourceIndex
|
|
2626
|
+
targetIndex: sourceIndex,
|
|
2627
|
+
sourceRow: targetRow,
|
|
2628
|
+
targetRow: sourceRow
|
|
2216
2629
|
}, true);
|
|
2217
2630
|
}
|
|
2218
2631
|
moveFormField(context, revert) {
|
|
@@ -2220,7 +2633,8 @@ class MoveFormFieldHandler {
|
|
|
2220
2633
|
sourceFormField,
|
|
2221
2634
|
targetFormField,
|
|
2222
2635
|
sourceIndex,
|
|
2223
|
-
targetIndex
|
|
2636
|
+
targetIndex,
|
|
2637
|
+
targetRow
|
|
2224
2638
|
} = context;
|
|
2225
2639
|
let {
|
|
2226
2640
|
schema
|
|
@@ -2236,11 +2650,15 @@ class MoveFormFieldHandler {
|
|
|
2236
2650
|
targetIndex--;
|
|
2237
2651
|
}
|
|
2238
2652
|
}
|
|
2653
|
+
const formField = get(schema, [...sourcePath, sourceIndex]);
|
|
2654
|
+
|
|
2655
|
+
// (1) Add to row
|
|
2656
|
+
updateRow(formField, targetRow ? targetRow.id : null);
|
|
2239
2657
|
|
|
2240
|
-
// (
|
|
2658
|
+
// (2) Move form field
|
|
2241
2659
|
mutate(get(schema, sourcePath), sourceIndex, targetIndex);
|
|
2242
2660
|
|
|
2243
|
-
// (
|
|
2661
|
+
// (3) Update paths of new form field and its siblings
|
|
2244
2662
|
get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
2245
2663
|
} else {
|
|
2246
2664
|
const formField = get(schema, [...sourcePath, sourceIndex]);
|
|
@@ -2253,10 +2671,13 @@ class MoveFormFieldHandler {
|
|
|
2253
2671
|
get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
2254
2672
|
const targetPath = [...targetFormField._path, 'components'];
|
|
2255
2673
|
|
|
2256
|
-
// (3) Add
|
|
2674
|
+
// (3) Add to row
|
|
2675
|
+
updateRow(formField, targetRow ? targetRow.id : null);
|
|
2676
|
+
|
|
2677
|
+
// (4) Add form field
|
|
2257
2678
|
arrayAdd$1(get(schema, targetPath), targetIndex, formField);
|
|
2258
2679
|
|
|
2259
|
-
// (
|
|
2680
|
+
// (5) Update paths of siblings
|
|
2260
2681
|
get(schema, targetPath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
2261
2682
|
}
|
|
2262
2683
|
|
|
@@ -2448,13 +2869,15 @@ class Modeling {
|
|
|
2448
2869
|
};
|
|
2449
2870
|
this._commandStack.execute('formField.edit', context);
|
|
2450
2871
|
}
|
|
2451
|
-
moveFormField(formField, sourceFormField, targetFormField, sourceIndex, targetIndex) {
|
|
2872
|
+
moveFormField(formField, sourceFormField, targetFormField, sourceIndex, targetIndex, sourceRow, targetRow) {
|
|
2452
2873
|
const context = {
|
|
2453
2874
|
formField,
|
|
2454
2875
|
sourceFormField,
|
|
2455
2876
|
targetFormField,
|
|
2456
2877
|
sourceIndex,
|
|
2457
|
-
targetIndex
|
|
2878
|
+
targetIndex,
|
|
2879
|
+
sourceRow,
|
|
2880
|
+
targetRow
|
|
2458
2881
|
};
|
|
2459
2882
|
this._commandStack.execute('formField.move', context);
|
|
2460
2883
|
}
|
|
@@ -2613,6 +3036,44 @@ forEach(hooks, function (hook) {
|
|
|
2613
3036
|
};
|
|
2614
3037
|
});
|
|
2615
3038
|
|
|
3039
|
+
class FormLayoutUpdater extends CommandInterceptor {
|
|
3040
|
+
constructor(eventBus, formLayouter, modeling, formEditor) {
|
|
3041
|
+
super(eventBus);
|
|
3042
|
+
this._eventBus = eventBus;
|
|
3043
|
+
this._formLayouter = formLayouter;
|
|
3044
|
+
this._modeling = modeling;
|
|
3045
|
+
this._formEditor = formEditor;
|
|
3046
|
+
|
|
3047
|
+
// @ts-ignore
|
|
3048
|
+
this.preExecute(['formField.add', 'formField.remove', 'formField.move', 'id.updateClaim'], event => this.updateRowIds(event));
|
|
3049
|
+
|
|
3050
|
+
// we need that as the state got updates
|
|
3051
|
+
// on the next tick (not in post execute)
|
|
3052
|
+
eventBus.on('changed', context => {
|
|
3053
|
+
const {
|
|
3054
|
+
schema
|
|
3055
|
+
} = context;
|
|
3056
|
+
this.updateLayout(schema);
|
|
3057
|
+
});
|
|
3058
|
+
}
|
|
3059
|
+
updateLayout(schema) {
|
|
3060
|
+
this._formLayouter.clear();
|
|
3061
|
+
this._formLayouter.calculateLayout(clone(schema));
|
|
3062
|
+
}
|
|
3063
|
+
updateRowIds(event) {
|
|
3064
|
+
const {
|
|
3065
|
+
schema
|
|
3066
|
+
} = this._formEditor._getState();
|
|
3067
|
+
|
|
3068
|
+
// make sure rows are persisted in schema (e.g. for migration case)
|
|
3069
|
+
schema.components.forEach(formField => {
|
|
3070
|
+
const row = this._formLayouter.getRowForField(formField);
|
|
3071
|
+
updateRow(formField, row.id);
|
|
3072
|
+
});
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
FormLayoutUpdater.$inject = ['eventBus', 'formLayouter', 'modeling', 'formEditor'];
|
|
3076
|
+
|
|
2616
3077
|
class IdBehavior extends CommandInterceptor {
|
|
2617
3078
|
constructor(eventBus, modeling) {
|
|
2618
3079
|
super(eventBus);
|
|
@@ -3134,7 +3595,8 @@ var commandModule = {
|
|
|
3134
3595
|
|
|
3135
3596
|
var ModelingModule = {
|
|
3136
3597
|
__depends__: [behaviorModule, commandModule],
|
|
3137
|
-
__init__: ['modeling'],
|
|
3598
|
+
__init__: ['formLayoutUpdater', 'modeling'],
|
|
3599
|
+
formLayoutUpdater: ['type', FormLayoutUpdater],
|
|
3138
3600
|
modeling: ['type', Modeling]
|
|
3139
3601
|
};
|
|
3140
3602
|
|
|
@@ -3430,19 +3892,19 @@ const ErrorsContext = createContext({
|
|
|
3430
3892
|
errors: {}
|
|
3431
3893
|
});
|
|
3432
3894
|
|
|
3433
|
-
/**
|
|
3434
|
-
* @typedef {Function} <propertiesPanel.showEntry> callback
|
|
3435
|
-
*
|
|
3436
|
-
* @example
|
|
3437
|
-
*
|
|
3438
|
-
* useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
|
|
3439
|
-
* // ...
|
|
3440
|
-
* });
|
|
3441
|
-
*
|
|
3442
|
-
* @param {Object} context
|
|
3443
|
-
* @param {boolean} [context.focus]
|
|
3444
|
-
*
|
|
3445
|
-
* @returns void
|
|
3895
|
+
/**
|
|
3896
|
+
* @typedef {Function} <propertiesPanel.showEntry> callback
|
|
3897
|
+
*
|
|
3898
|
+
* @example
|
|
3899
|
+
*
|
|
3900
|
+
* useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
|
|
3901
|
+
* // ...
|
|
3902
|
+
* });
|
|
3903
|
+
*
|
|
3904
|
+
* @param {Object} context
|
|
3905
|
+
* @param {boolean} [context.focus]
|
|
3906
|
+
*
|
|
3907
|
+
* @returns void
|
|
3446
3908
|
*/
|
|
3447
3909
|
const EventContext = createContext({
|
|
3448
3910
|
eventBus: null
|
|
@@ -3454,20 +3916,20 @@ const LayoutContext = createContext({
|
|
|
3454
3916
|
setLayoutForKey: () => {}
|
|
3455
3917
|
});
|
|
3456
3918
|
|
|
3457
|
-
/**
|
|
3458
|
-
* Accesses the global DescriptionContext and returns a description for a given id and element.
|
|
3459
|
-
*
|
|
3460
|
-
* @example
|
|
3461
|
-
* ```jsx
|
|
3462
|
-
* function TextField(props) {
|
|
3463
|
-
* const description = useDescriptionContext('input1', element);
|
|
3464
|
-
* }
|
|
3465
|
-
* ```
|
|
3466
|
-
*
|
|
3467
|
-
* @param {string} id
|
|
3468
|
-
* @param {object} element
|
|
3469
|
-
*
|
|
3470
|
-
* @returns {string}
|
|
3919
|
+
/**
|
|
3920
|
+
* Accesses the global DescriptionContext and returns a description for a given id and element.
|
|
3921
|
+
*
|
|
3922
|
+
* @example
|
|
3923
|
+
* ```jsx
|
|
3924
|
+
* function TextField(props) {
|
|
3925
|
+
* const description = useDescriptionContext('input1', element);
|
|
3926
|
+
* }
|
|
3927
|
+
* ```
|
|
3928
|
+
*
|
|
3929
|
+
* @param {string} id
|
|
3930
|
+
* @param {object} element
|
|
3931
|
+
*
|
|
3932
|
+
* @returns {string}
|
|
3471
3933
|
*/
|
|
3472
3934
|
function useDescriptionContext(id, element) {
|
|
3473
3935
|
const {
|
|
@@ -3482,11 +3944,11 @@ function useError(id) {
|
|
|
3482
3944
|
return errors[id];
|
|
3483
3945
|
}
|
|
3484
3946
|
|
|
3485
|
-
/**
|
|
3486
|
-
* Subscribe to an event immediately. Update subscription after inputs changed.
|
|
3487
|
-
*
|
|
3488
|
-
* @param {string} event
|
|
3489
|
-
* @param {Function} callback
|
|
3947
|
+
/**
|
|
3948
|
+
* Subscribe to an event immediately. Update subscription after inputs changed.
|
|
3949
|
+
*
|
|
3950
|
+
* @param {string} event
|
|
3951
|
+
* @param {Function} callback
|
|
3490
3952
|
*/
|
|
3491
3953
|
function useEvent(event, callback, eventBus) {
|
|
3492
3954
|
const eventContext = useContext(EventContext);
|
|
@@ -3516,20 +3978,20 @@ function useEvent(event, callback, eventBus) {
|
|
|
3516
3978
|
}, [callback, event, eventBus]);
|
|
3517
3979
|
}
|
|
3518
3980
|
|
|
3519
|
-
/**
|
|
3520
|
-
* Creates a state that persists in the global LayoutContext.
|
|
3521
|
-
*
|
|
3522
|
-
* @example
|
|
3523
|
-
* ```jsx
|
|
3524
|
-
* function Group(props) {
|
|
3525
|
-
* const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
|
|
3526
|
-
* }
|
|
3527
|
-
* ```
|
|
3528
|
-
*
|
|
3529
|
-
* @param {(string|number)[]} path
|
|
3530
|
-
* @param {any} [defaultValue]
|
|
3531
|
-
*
|
|
3532
|
-
* @returns {[ any, Function ]}
|
|
3981
|
+
/**
|
|
3982
|
+
* Creates a state that persists in the global LayoutContext.
|
|
3983
|
+
*
|
|
3984
|
+
* @example
|
|
3985
|
+
* ```jsx
|
|
3986
|
+
* function Group(props) {
|
|
3987
|
+
* const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
|
|
3988
|
+
* }
|
|
3989
|
+
* ```
|
|
3990
|
+
*
|
|
3991
|
+
* @param {(string|number)[]} path
|
|
3992
|
+
* @param {any} [defaultValue]
|
|
3993
|
+
*
|
|
3994
|
+
* @returns {[ any, Function ]}
|
|
3533
3995
|
*/
|
|
3534
3996
|
function useLayoutState(path, defaultValue) {
|
|
3535
3997
|
const {
|
|
@@ -3537,22 +3999,17 @@ function useLayoutState(path, defaultValue) {
|
|
|
3537
3999
|
setLayoutForKey
|
|
3538
4000
|
} = useContext(LayoutContext);
|
|
3539
4001
|
const layoutForKey = getLayoutForKey(path, defaultValue);
|
|
3540
|
-
const
|
|
3541
|
-
const setState = newValue => {
|
|
3542
|
-
// (1) set component state
|
|
3543
|
-
set(newValue);
|
|
3544
|
-
|
|
3545
|
-
// (2) set context
|
|
4002
|
+
const setState = useCallback(newValue => {
|
|
3546
4003
|
setLayoutForKey(path, newValue);
|
|
3547
|
-
};
|
|
3548
|
-
return [
|
|
4004
|
+
}, [setLayoutForKey]);
|
|
4005
|
+
return [layoutForKey, setState];
|
|
3549
4006
|
}
|
|
3550
4007
|
|
|
3551
|
-
/**
|
|
3552
|
-
* @pinussilvestrus: we need to introduce our own hook to persist the previous
|
|
3553
|
-
* state on updates.
|
|
3554
|
-
*
|
|
3555
|
-
* cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
|
|
4008
|
+
/**
|
|
4009
|
+
* @pinussilvestrus: we need to introduce our own hook to persist the previous
|
|
4010
|
+
* state on updates.
|
|
4011
|
+
*
|
|
4012
|
+
* cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
|
|
3556
4013
|
*/
|
|
3557
4014
|
|
|
3558
4015
|
function usePrevious(value) {
|
|
@@ -3563,12 +4020,12 @@ function usePrevious(value) {
|
|
|
3563
4020
|
return ref.current;
|
|
3564
4021
|
}
|
|
3565
4022
|
|
|
3566
|
-
/**
|
|
3567
|
-
* Subscribe to `propertiesPanel.showEntry`.
|
|
3568
|
-
*
|
|
3569
|
-
* @param {string} id
|
|
3570
|
-
*
|
|
3571
|
-
* @returns {import('preact').Ref}
|
|
4023
|
+
/**
|
|
4024
|
+
* Subscribe to `propertiesPanel.showEntry`.
|
|
4025
|
+
*
|
|
4026
|
+
* @param {string} id
|
|
4027
|
+
*
|
|
4028
|
+
* @returns {import('preact').Ref}
|
|
3572
4029
|
*/
|
|
3573
4030
|
function useShowEntryEvent(id) {
|
|
3574
4031
|
const {
|
|
@@ -3599,20 +4056,20 @@ function useShowEntryEvent(id) {
|
|
|
3599
4056
|
return ref;
|
|
3600
4057
|
}
|
|
3601
4058
|
|
|
3602
|
-
/**
|
|
3603
|
-
* @callback setSticky
|
|
3604
|
-
* @param {boolean} value
|
|
4059
|
+
/**
|
|
4060
|
+
* @callback setSticky
|
|
4061
|
+
* @param {boolean} value
|
|
3605
4062
|
*/
|
|
3606
4063
|
|
|
3607
|
-
/**
|
|
3608
|
-
* Use IntersectionObserver to identify when DOM element is in sticky mode.
|
|
3609
|
-
* If sticky is observered setSticky(true) will be called.
|
|
3610
|
-
* If sticky mode is left, setSticky(false) will be called.
|
|
3611
|
-
*
|
|
3612
|
-
*
|
|
3613
|
-
* @param {Object} ref
|
|
3614
|
-
* @param {string} scrollContainerSelector
|
|
3615
|
-
* @param {setSticky} setSticky
|
|
4064
|
+
/**
|
|
4065
|
+
* Use IntersectionObserver to identify when DOM element is in sticky mode.
|
|
4066
|
+
* If sticky is observered setSticky(true) will be called.
|
|
4067
|
+
* If sticky mode is left, setSticky(false) will be called.
|
|
4068
|
+
*
|
|
4069
|
+
*
|
|
4070
|
+
* @param {Object} ref
|
|
4071
|
+
* @param {string} scrollContainerSelector
|
|
4072
|
+
* @param {setSticky} setSticky
|
|
3616
4073
|
*/
|
|
3617
4074
|
function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
|
|
3618
4075
|
useEffect(() => {
|
|
@@ -3651,19 +4108,19 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
|
|
|
3651
4108
|
}, [ref, scrollContainerSelector, setSticky]);
|
|
3652
4109
|
}
|
|
3653
4110
|
|
|
3654
|
-
/**
|
|
3655
|
-
* Creates a static function reference with changing body.
|
|
3656
|
-
* This is necessary when external libraries require a callback function
|
|
3657
|
-
* that has references to state variables.
|
|
3658
|
-
*
|
|
3659
|
-
* Usage:
|
|
3660
|
-
* const callback = useStaticCallback((val) => {val === currentState});
|
|
3661
|
-
*
|
|
3662
|
-
* The `callback` reference is static and can be safely used in external
|
|
3663
|
-
* libraries or as a prop that does not cause rerendering of children.
|
|
3664
|
-
*
|
|
3665
|
-
* @param {Function} callback function with changing reference
|
|
3666
|
-
* @returns {Function} static function reference
|
|
4111
|
+
/**
|
|
4112
|
+
* Creates a static function reference with changing body.
|
|
4113
|
+
* This is necessary when external libraries require a callback function
|
|
4114
|
+
* that has references to state variables.
|
|
4115
|
+
*
|
|
4116
|
+
* Usage:
|
|
4117
|
+
* const callback = useStaticCallback((val) => {val === currentState});
|
|
4118
|
+
*
|
|
4119
|
+
* The `callback` reference is static and can be safely used in external
|
|
4120
|
+
* libraries or as a prop that does not cause rerendering of children.
|
|
4121
|
+
*
|
|
4122
|
+
* @param {Function} callback function with changing reference
|
|
4123
|
+
* @returns {Function} static function reference
|
|
3667
4124
|
*/
|
|
3668
4125
|
function useStaticCallback(callback) {
|
|
3669
4126
|
const callbackRef = useRef(callback);
|
|
@@ -3755,13 +4212,13 @@ function DataMarker() {
|
|
|
3755
4212
|
});
|
|
3756
4213
|
}
|
|
3757
4214
|
|
|
3758
|
-
/**
|
|
3759
|
-
* @typedef { {
|
|
3760
|
-
* text: (element: object) => string,
|
|
3761
|
-
* icon?: (element: Object) => import('preact').Component
|
|
3762
|
-
* } } PlaceholderDefinition
|
|
3763
|
-
*
|
|
3764
|
-
* @param { PlaceholderDefinition } props
|
|
4215
|
+
/**
|
|
4216
|
+
* @typedef { {
|
|
4217
|
+
* text: (element: object) => string,
|
|
4218
|
+
* icon?: (element: Object) => import('preact').Component
|
|
4219
|
+
* } } PlaceholderDefinition
|
|
4220
|
+
*
|
|
4221
|
+
* @param { PlaceholderDefinition } props
|
|
3765
4222
|
*/
|
|
3766
4223
|
function Placeholder(props) {
|
|
3767
4224
|
const {
|
|
@@ -3786,72 +4243,72 @@ const DEFAULT_LAYOUT = {
|
|
|
3786
4243
|
};
|
|
3787
4244
|
const DEFAULT_DESCRIPTION = {};
|
|
3788
4245
|
|
|
3789
|
-
/**
|
|
3790
|
-
* @typedef { {
|
|
3791
|
-
* component: import('preact').Component,
|
|
3792
|
-
* id: String,
|
|
3793
|
-
* isEdited?: Function
|
|
3794
|
-
* } } EntryDefinition
|
|
3795
|
-
*
|
|
3796
|
-
* @typedef { {
|
|
3797
|
-
* autoFocusEntry: String,
|
|
3798
|
-
* autoOpen?: Boolean,
|
|
3799
|
-
* entries: Array<EntryDefinition>,
|
|
3800
|
-
* id: String,
|
|
3801
|
-
* label: String,
|
|
3802
|
-
* remove: (event: MouseEvent) => void
|
|
3803
|
-
* } } ListItemDefinition
|
|
3804
|
-
*
|
|
3805
|
-
* @typedef { {
|
|
3806
|
-
* add: (event: MouseEvent) => void,
|
|
3807
|
-
* component: import('preact').Component,
|
|
3808
|
-
* element: Object,
|
|
3809
|
-
* id: String,
|
|
3810
|
-
* items: Array<ListItemDefinition>,
|
|
3811
|
-
* label: String,
|
|
3812
|
-
* shouldSort?: Boolean,
|
|
3813
|
-
* shouldOpen?: Boolean
|
|
3814
|
-
* } } ListGroupDefinition
|
|
3815
|
-
*
|
|
3816
|
-
* @typedef { {
|
|
3817
|
-
* component?: import('preact').Component,
|
|
3818
|
-
* entries: Array<EntryDefinition>,
|
|
3819
|
-
* id: String,
|
|
3820
|
-
* label: String,
|
|
3821
|
-
* shouldOpen?: Boolean
|
|
3822
|
-
* } } GroupDefinition
|
|
3823
|
-
*
|
|
3824
|
-
* @typedef { {
|
|
3825
|
-
* [id: String]: GetDescriptionFunction
|
|
3826
|
-
* } } DescriptionConfig
|
|
3827
|
-
*
|
|
3828
|
-
* @callback { {
|
|
3829
|
-
* @param {string} id
|
|
3830
|
-
* @param {Object} element
|
|
3831
|
-
* @returns {string}
|
|
3832
|
-
* } } GetDescriptionFunction
|
|
3833
|
-
*
|
|
3834
|
-
* @typedef { {
|
|
3835
|
-
* getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
|
|
3836
|
-
* getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
|
|
3837
|
-
* } } PlaceholderProvider
|
|
3838
|
-
*
|
|
4246
|
+
/**
|
|
4247
|
+
* @typedef { {
|
|
4248
|
+
* component: import('preact').Component,
|
|
4249
|
+
* id: String,
|
|
4250
|
+
* isEdited?: Function
|
|
4251
|
+
* } } EntryDefinition
|
|
4252
|
+
*
|
|
4253
|
+
* @typedef { {
|
|
4254
|
+
* autoFocusEntry: String,
|
|
4255
|
+
* autoOpen?: Boolean,
|
|
4256
|
+
* entries: Array<EntryDefinition>,
|
|
4257
|
+
* id: String,
|
|
4258
|
+
* label: String,
|
|
4259
|
+
* remove: (event: MouseEvent) => void
|
|
4260
|
+
* } } ListItemDefinition
|
|
4261
|
+
*
|
|
4262
|
+
* @typedef { {
|
|
4263
|
+
* add: (event: MouseEvent) => void,
|
|
4264
|
+
* component: import('preact').Component,
|
|
4265
|
+
* element: Object,
|
|
4266
|
+
* id: String,
|
|
4267
|
+
* items: Array<ListItemDefinition>,
|
|
4268
|
+
* label: String,
|
|
4269
|
+
* shouldSort?: Boolean,
|
|
4270
|
+
* shouldOpen?: Boolean
|
|
4271
|
+
* } } ListGroupDefinition
|
|
4272
|
+
*
|
|
4273
|
+
* @typedef { {
|
|
4274
|
+
* component?: import('preact').Component,
|
|
4275
|
+
* entries: Array<EntryDefinition>,
|
|
4276
|
+
* id: String,
|
|
4277
|
+
* label: String,
|
|
4278
|
+
* shouldOpen?: Boolean
|
|
4279
|
+
* } } GroupDefinition
|
|
4280
|
+
*
|
|
4281
|
+
* @typedef { {
|
|
4282
|
+
* [id: String]: GetDescriptionFunction
|
|
4283
|
+
* } } DescriptionConfig
|
|
4284
|
+
*
|
|
4285
|
+
* @callback { {
|
|
4286
|
+
* @param {string} id
|
|
4287
|
+
* @param {Object} element
|
|
4288
|
+
* @returns {string}
|
|
4289
|
+
* } } GetDescriptionFunction
|
|
4290
|
+
*
|
|
4291
|
+
* @typedef { {
|
|
4292
|
+
* getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
|
|
4293
|
+
* getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
|
|
4294
|
+
* } } PlaceholderProvider
|
|
4295
|
+
*
|
|
3839
4296
|
*/
|
|
3840
4297
|
|
|
3841
|
-
/**
|
|
3842
|
-
* A basic properties panel component. Describes *how* content will be rendered, accepts
|
|
3843
|
-
* data from implementor to describe *what* will be rendered.
|
|
3844
|
-
*
|
|
3845
|
-
* @param {Object} props
|
|
3846
|
-
* @param {Object|Array} props.element
|
|
3847
|
-
* @param {import('./components/Header').HeaderProvider} props.headerProvider
|
|
3848
|
-
* @param {PlaceholderProvider} [props.placeholderProvider]
|
|
3849
|
-
* @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
|
|
3850
|
-
* @param {Object} [props.layoutConfig]
|
|
3851
|
-
* @param {Function} [props.layoutChanged]
|
|
3852
|
-
* @param {DescriptionConfig} [props.descriptionConfig]
|
|
3853
|
-
* @param {Function} [props.descriptionLoaded]
|
|
3854
|
-
* @param {Object} [props.eventBus]
|
|
4298
|
+
/**
|
|
4299
|
+
* A basic properties panel component. Describes *how* content will be rendered, accepts
|
|
4300
|
+
* data from implementor to describe *what* will be rendered.
|
|
4301
|
+
*
|
|
4302
|
+
* @param {Object} props
|
|
4303
|
+
* @param {Object|Array} props.element
|
|
4304
|
+
* @param {import('./components/Header').HeaderProvider} props.headerProvider
|
|
4305
|
+
* @param {PlaceholderProvider} [props.placeholderProvider]
|
|
4306
|
+
* @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
|
|
4307
|
+
* @param {Object} [props.layoutConfig]
|
|
4308
|
+
* @param {Function} [props.layoutChanged]
|
|
4309
|
+
* @param {DescriptionConfig} [props.descriptionConfig]
|
|
4310
|
+
* @param {Function} [props.descriptionLoaded]
|
|
4311
|
+
* @param {Object} [props.eventBus]
|
|
3855
4312
|
*/
|
|
3856
4313
|
function PropertiesPanel(props) {
|
|
3857
4314
|
const {
|
|
@@ -3859,15 +4316,21 @@ function PropertiesPanel(props) {
|
|
|
3859
4316
|
headerProvider,
|
|
3860
4317
|
placeholderProvider,
|
|
3861
4318
|
groups,
|
|
3862
|
-
layoutConfig
|
|
4319
|
+
layoutConfig,
|
|
3863
4320
|
layoutChanged,
|
|
3864
|
-
descriptionConfig
|
|
4321
|
+
descriptionConfig,
|
|
3865
4322
|
descriptionLoaded,
|
|
3866
4323
|
eventBus
|
|
3867
4324
|
} = props;
|
|
3868
4325
|
|
|
3869
4326
|
// set-up layout context
|
|
3870
4327
|
const [layout, setLayout] = useState(createLayout(layoutConfig));
|
|
4328
|
+
|
|
4329
|
+
// react to external changes in the layout config
|
|
4330
|
+
useUpdateEffect(() => {
|
|
4331
|
+
const newLayout = createLayout(layoutConfig);
|
|
4332
|
+
setLayout(newLayout);
|
|
4333
|
+
}, [layoutConfig]);
|
|
3871
4334
|
useEffect(() => {
|
|
3872
4335
|
if (typeof layoutChanged === 'function') {
|
|
3873
4336
|
layoutChanged(layout);
|
|
@@ -3889,10 +4352,12 @@ function PropertiesPanel(props) {
|
|
|
3889
4352
|
};
|
|
3890
4353
|
|
|
3891
4354
|
// set-up description context
|
|
3892
|
-
const description = createDescriptionContext(descriptionConfig);
|
|
3893
|
-
|
|
3894
|
-
descriptionLoaded
|
|
3895
|
-
|
|
4355
|
+
const description = useMemo(() => createDescriptionContext(descriptionConfig), [descriptionConfig]);
|
|
4356
|
+
useEffect(() => {
|
|
4357
|
+
if (typeof descriptionLoaded === 'function') {
|
|
4358
|
+
descriptionLoaded(description);
|
|
4359
|
+
}
|
|
4360
|
+
}, [description, descriptionLoaded]);
|
|
3896
4361
|
const getDescriptionForId = (id, element) => {
|
|
3897
4362
|
return description[id] && description[id](element);
|
|
3898
4363
|
};
|
|
@@ -3967,18 +4432,37 @@ function PropertiesPanel(props) {
|
|
|
3967
4432
|
|
|
3968
4433
|
// helpers //////////////////
|
|
3969
4434
|
|
|
3970
|
-
function createLayout(overrides) {
|
|
4435
|
+
function createLayout(overrides = {}, defaults = DEFAULT_LAYOUT) {
|
|
3971
4436
|
return {
|
|
3972
|
-
...
|
|
4437
|
+
...defaults,
|
|
3973
4438
|
...overrides
|
|
3974
4439
|
};
|
|
3975
4440
|
}
|
|
3976
|
-
function createDescriptionContext(overrides) {
|
|
4441
|
+
function createDescriptionContext(overrides = {}) {
|
|
3977
4442
|
return {
|
|
3978
4443
|
...DEFAULT_DESCRIPTION,
|
|
3979
4444
|
...overrides
|
|
3980
4445
|
};
|
|
3981
4446
|
}
|
|
4447
|
+
|
|
4448
|
+
// hooks //////////////////
|
|
4449
|
+
|
|
4450
|
+
/**
|
|
4451
|
+
* This hook behaves like useEffect, but does not trigger on the first render.
|
|
4452
|
+
*
|
|
4453
|
+
* @param {Function} effect
|
|
4454
|
+
* @param {Array} deps
|
|
4455
|
+
*/
|
|
4456
|
+
function useUpdateEffect(effect, deps) {
|
|
4457
|
+
const isMounted = useRef(false);
|
|
4458
|
+
useEffect(() => {
|
|
4459
|
+
if (isMounted.current) {
|
|
4460
|
+
return effect();
|
|
4461
|
+
} else {
|
|
4462
|
+
isMounted.current = true;
|
|
4463
|
+
}
|
|
4464
|
+
}, deps);
|
|
4465
|
+
}
|
|
3982
4466
|
function CollapsibleEntry(props) {
|
|
3983
4467
|
const {
|
|
3984
4468
|
element,
|
|
@@ -4074,10 +4558,10 @@ function ListItem(props) {
|
|
|
4074
4558
|
})
|
|
4075
4559
|
});
|
|
4076
4560
|
}
|
|
4077
|
-
const noop$
|
|
4561
|
+
const noop$3 = () => {};
|
|
4078
4562
|
|
|
4079
|
-
/**
|
|
4080
|
-
* @param {import('../PropertiesPanel').ListGroupDefinition} props
|
|
4563
|
+
/**
|
|
4564
|
+
* @param {import('../PropertiesPanel').ListGroupDefinition} props
|
|
4081
4565
|
*/
|
|
4082
4566
|
function ListGroup(props) {
|
|
4083
4567
|
const {
|
|
@@ -4095,6 +4579,9 @@ function ListGroup(props) {
|
|
|
4095
4579
|
const onShow = useCallback(() => setOpen(true), [setOpen]);
|
|
4096
4580
|
const [ordering, setOrdering] = useState([]);
|
|
4097
4581
|
const [newItemAdded, setNewItemAdded] = useState(false);
|
|
4582
|
+
|
|
4583
|
+
// Flag to mark that add button was clicked in the last render cycle
|
|
4584
|
+
const [addTriggered, setAddTriggered] = useState(false);
|
|
4098
4585
|
const prevItems = usePrevious(items);
|
|
4099
4586
|
const prevElement = usePrevious(element);
|
|
4100
4587
|
const elementChanged = element !== prevElement;
|
|
@@ -4116,6 +4603,8 @@ function ListGroup(props) {
|
|
|
4116
4603
|
|
|
4117
4604
|
// (1) items were added
|
|
4118
4605
|
useEffect(() => {
|
|
4606
|
+
// reset addTriggered flag
|
|
4607
|
+
setAddTriggered(false);
|
|
4119
4608
|
if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
|
|
4120
4609
|
let add = [];
|
|
4121
4610
|
items.forEach(item => {
|
|
@@ -4125,14 +4614,18 @@ function ListGroup(props) {
|
|
|
4125
4614
|
});
|
|
4126
4615
|
let newOrdering = ordering;
|
|
4127
4616
|
|
|
4128
|
-
// open if not open and
|
|
4129
|
-
|
|
4617
|
+
// open if not open, configured and triggered by add button
|
|
4618
|
+
//
|
|
4619
|
+
// TODO(marstamm): remove once we refactor layout handling for listGroups.
|
|
4620
|
+
// Ideally, opening should be handled as part of the `add` callback and
|
|
4621
|
+
// not be a concern for the ListGroup component.
|
|
4622
|
+
if (addTriggered && !open && shouldOpen) {
|
|
4130
4623
|
toggleOpen();
|
|
4624
|
+
}
|
|
4131
4625
|
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
}
|
|
4626
|
+
// filter when not open and configured
|
|
4627
|
+
if (!open && shouldSort) {
|
|
4628
|
+
newOrdering = createOrdering(sortItems(items));
|
|
4136
4629
|
}
|
|
4137
4630
|
|
|
4138
4631
|
// add new items on top or bottom depending on sorting behavior
|
|
@@ -4143,11 +4636,11 @@ function ListGroup(props) {
|
|
|
4143
4636
|
newOrdering.push(...add);
|
|
4144
4637
|
}
|
|
4145
4638
|
setOrdering(newOrdering);
|
|
4146
|
-
setNewItemAdded(
|
|
4639
|
+
setNewItemAdded(addTriggered);
|
|
4147
4640
|
} else {
|
|
4148
4641
|
setNewItemAdded(false);
|
|
4149
4642
|
}
|
|
4150
|
-
}, [items, open, shouldHandleEffects]);
|
|
4643
|
+
}, [items, open, shouldHandleEffects, addTriggered]);
|
|
4151
4644
|
|
|
4152
4645
|
// (2) sort items on open if shouldSort is set
|
|
4153
4646
|
useEffect(() => {
|
|
@@ -4177,13 +4670,17 @@ function ListGroup(props) {
|
|
|
4177
4670
|
...useContext(LayoutContext),
|
|
4178
4671
|
onShow
|
|
4179
4672
|
};
|
|
4673
|
+
const handleAddClick = e => {
|
|
4674
|
+
setAddTriggered(true);
|
|
4675
|
+
add(e);
|
|
4676
|
+
};
|
|
4180
4677
|
return jsxs("div", {
|
|
4181
4678
|
class: "bio-properties-panel-group",
|
|
4182
4679
|
"data-group-id": 'group-' + id,
|
|
4183
4680
|
ref: groupRef,
|
|
4184
4681
|
children: [jsxs("div", {
|
|
4185
4682
|
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
4186
|
-
onClick: hasItems ? toggleOpen : noop$
|
|
4683
|
+
onClick: hasItems ? toggleOpen : noop$3,
|
|
4187
4684
|
children: [jsx("div", {
|
|
4188
4685
|
title: label,
|
|
4189
4686
|
class: "bio-properties-panel-group-header-title",
|
|
@@ -4193,7 +4690,7 @@ function ListGroup(props) {
|
|
|
4193
4690
|
children: [add ? jsxs("button", {
|
|
4194
4691
|
title: "Create new list item",
|
|
4195
4692
|
class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
|
|
4196
|
-
onClick:
|
|
4693
|
+
onClick: handleAddClick,
|
|
4197
4694
|
children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
|
|
4198
4695
|
class: "bio-properties-panel-add-entry-label",
|
|
4199
4696
|
children: "Create"
|
|
@@ -4223,8 +4720,9 @@ function ListGroup(props) {
|
|
|
4223
4720
|
id
|
|
4224
4721
|
} = item;
|
|
4225
4722
|
|
|
4226
|
-
// if item was added, open
|
|
4227
|
-
|
|
4723
|
+
// if item was added, open it
|
|
4724
|
+
// Existing items will not be affected as autoOpen is only applied on first render
|
|
4725
|
+
const autoOpen = newItemAdded;
|
|
4228
4726
|
return createElement(ListItem, {
|
|
4229
4727
|
...item,
|
|
4230
4728
|
autoOpen: autoOpen,
|
|
@@ -4240,8 +4738,8 @@ function ListGroup(props) {
|
|
|
4240
4738
|
|
|
4241
4739
|
// helpers ////////////////////
|
|
4242
4740
|
|
|
4243
|
-
/**
|
|
4244
|
-
* Sorts given items alphanumeric by label
|
|
4741
|
+
/**
|
|
4742
|
+
* Sorts given items alphanumeric by label
|
|
4245
4743
|
*/
|
|
4246
4744
|
function sortItems(items) {
|
|
4247
4745
|
return sortBy(items, i => i.label.toLowerCase());
|
|
@@ -4315,17 +4813,17 @@ function Checkbox(props) {
|
|
|
4315
4813
|
});
|
|
4316
4814
|
}
|
|
4317
4815
|
|
|
4318
|
-
/**
|
|
4319
|
-
* @param {Object} props
|
|
4320
|
-
* @param {Object} props.element
|
|
4321
|
-
* @param {String} props.id
|
|
4322
|
-
* @param {String} props.description
|
|
4323
|
-
* @param {String} props.label
|
|
4324
|
-
* @param {Function} props.getValue
|
|
4325
|
-
* @param {Function} props.setValue
|
|
4326
|
-
* @param {Function} props.onFocus
|
|
4327
|
-
* @param {Function} props.onBlur
|
|
4328
|
-
* @param {boolean} [props.disabled]
|
|
4816
|
+
/**
|
|
4817
|
+
* @param {Object} props
|
|
4818
|
+
* @param {Object} props.element
|
|
4819
|
+
* @param {String} props.id
|
|
4820
|
+
* @param {String} props.description
|
|
4821
|
+
* @param {String} props.label
|
|
4822
|
+
* @param {Function} props.getValue
|
|
4823
|
+
* @param {Function} props.setValue
|
|
4824
|
+
* @param {Function} props.onFocus
|
|
4825
|
+
* @param {Function} props.onBlur
|
|
4826
|
+
* @param {boolean} [props.disabled]
|
|
4329
4827
|
*/
|
|
4330
4828
|
function CheckboxEntry(props) {
|
|
4331
4829
|
const {
|
|
@@ -4362,7 +4860,7 @@ function CheckboxEntry(props) {
|
|
|
4362
4860
|
})]
|
|
4363
4861
|
});
|
|
4364
4862
|
}
|
|
4365
|
-
function isEdited$
|
|
4863
|
+
function isEdited$8(node) {
|
|
4366
4864
|
return node && !!node.checked;
|
|
4367
4865
|
}
|
|
4368
4866
|
|
|
@@ -4371,6 +4869,87 @@ function isEdited$7(node) {
|
|
|
4371
4869
|
function prefixId$7(id) {
|
|
4372
4870
|
return `bio-properties-panel-${id}`;
|
|
4373
4871
|
}
|
|
4872
|
+
const useBufferedFocus$1 = function (editor, ref) {
|
|
4873
|
+
const [buffer, setBuffer] = useState(undefined);
|
|
4874
|
+
ref.current = useMemo(() => ({
|
|
4875
|
+
focus: offset => {
|
|
4876
|
+
if (editor) {
|
|
4877
|
+
editor.focus(offset);
|
|
4878
|
+
} else {
|
|
4879
|
+
if (typeof offset === 'undefined') {
|
|
4880
|
+
offset = Infinity;
|
|
4881
|
+
}
|
|
4882
|
+
setBuffer(offset);
|
|
4883
|
+
}
|
|
4884
|
+
}
|
|
4885
|
+
}), [editor]);
|
|
4886
|
+
useEffect(() => {
|
|
4887
|
+
if (typeof buffer !== 'undefined' && editor) {
|
|
4888
|
+
editor.focus(buffer);
|
|
4889
|
+
setBuffer(false);
|
|
4890
|
+
}
|
|
4891
|
+
}, [editor, buffer]);
|
|
4892
|
+
};
|
|
4893
|
+
const CodeEditor$1 = forwardRef((props, ref) => {
|
|
4894
|
+
const {
|
|
4895
|
+
onInput,
|
|
4896
|
+
disabled,
|
|
4897
|
+
tooltipContainer,
|
|
4898
|
+
enableGutters,
|
|
4899
|
+
value,
|
|
4900
|
+
onLint = () => {},
|
|
4901
|
+
contentAttributes = {},
|
|
4902
|
+
hostLanguage = null,
|
|
4903
|
+
singleLine = false
|
|
4904
|
+
} = props;
|
|
4905
|
+
const inputRef = useRef();
|
|
4906
|
+
const [editor, setEditor] = useState();
|
|
4907
|
+
const [localValue, setLocalValue] = useState(value || '');
|
|
4908
|
+
useBufferedFocus$1(editor, ref);
|
|
4909
|
+
const handleInput = useStaticCallback(newValue => {
|
|
4910
|
+
onInput(newValue);
|
|
4911
|
+
setLocalValue(newValue);
|
|
4912
|
+
});
|
|
4913
|
+
useEffect(() => {
|
|
4914
|
+
let editor;
|
|
4915
|
+
editor = new FeelersEditor({
|
|
4916
|
+
container: inputRef.current,
|
|
4917
|
+
onChange: handleInput,
|
|
4918
|
+
value: localValue,
|
|
4919
|
+
onLint,
|
|
4920
|
+
contentAttributes,
|
|
4921
|
+
tooltipContainer,
|
|
4922
|
+
enableGutters,
|
|
4923
|
+
hostLanguage,
|
|
4924
|
+
singleLine
|
|
4925
|
+
});
|
|
4926
|
+
setEditor(editor);
|
|
4927
|
+
return () => {
|
|
4928
|
+
onLint([]);
|
|
4929
|
+
inputRef.current.innerHTML = '';
|
|
4930
|
+
setEditor(null);
|
|
4931
|
+
};
|
|
4932
|
+
}, []);
|
|
4933
|
+
useEffect(() => {
|
|
4934
|
+
if (!editor) {
|
|
4935
|
+
return;
|
|
4936
|
+
}
|
|
4937
|
+
if (value === localValue) {
|
|
4938
|
+
return;
|
|
4939
|
+
}
|
|
4940
|
+
editor.setValue(value);
|
|
4941
|
+
setLocalValue(value);
|
|
4942
|
+
}, [value]);
|
|
4943
|
+
const handleClick = () => {
|
|
4944
|
+
ref.current.focus();
|
|
4945
|
+
};
|
|
4946
|
+
return jsx("div", {
|
|
4947
|
+
name: props.name,
|
|
4948
|
+
class: classnames('bio-properties-panel-feelers-editor bio-properties-panel-input', localValue ? 'edited' : null, disabled ? 'disabled' : null),
|
|
4949
|
+
ref: inputRef,
|
|
4950
|
+
onClick: handleClick
|
|
4951
|
+
});
|
|
4952
|
+
});
|
|
4374
4953
|
const useBufferedFocus = function (editor, ref) {
|
|
4375
4954
|
const [buffer, setBuffer] = useState(undefined);
|
|
4376
4955
|
ref.current = useMemo(() => ({
|
|
@@ -4413,10 +4992,10 @@ const CodeEditor = forwardRef((props, ref) => {
|
|
|
4413
4992
|
useEffect(() => {
|
|
4414
4993
|
let editor;
|
|
4415
4994
|
|
|
4416
|
-
/* Trigger FEEL toggle when
|
|
4417
|
-
*
|
|
4418
|
-
* - `backspace` is pressed
|
|
4419
|
-
* - AND the cursor is at the beginning of the input
|
|
4995
|
+
/* Trigger FEEL toggle when
|
|
4996
|
+
*
|
|
4997
|
+
* - `backspace` is pressed
|
|
4998
|
+
* - AND the cursor is at the beginning of the input
|
|
4420
4999
|
*/
|
|
4421
5000
|
const onKeyDown = e => {
|
|
4422
5001
|
if (e.key !== 'Backspace' || !editor) {
|
|
@@ -4485,12 +5064,12 @@ function FeelIndicator(props) {
|
|
|
4485
5064
|
children: "="
|
|
4486
5065
|
});
|
|
4487
5066
|
}
|
|
4488
|
-
const noop$
|
|
5067
|
+
const noop$2 = () => {};
|
|
4489
5068
|
|
|
4490
|
-
/**
|
|
4491
|
-
* @param {Object} props
|
|
4492
|
-
* @param {Object} props.label
|
|
4493
|
-
* @param {String} props.feel
|
|
5069
|
+
/**
|
|
5070
|
+
* @param {Object} props
|
|
5071
|
+
* @param {Object} props.label
|
|
5072
|
+
* @param {String} props.feel
|
|
4494
5073
|
*/
|
|
4495
5074
|
function FeelIcon(props) {
|
|
4496
5075
|
const {
|
|
@@ -4498,7 +5077,7 @@ function FeelIcon(props) {
|
|
|
4498
5077
|
feel = false,
|
|
4499
5078
|
active,
|
|
4500
5079
|
disabled = false,
|
|
4501
|
-
onClick = noop$
|
|
5080
|
+
onClick = noop$2
|
|
4502
5081
|
} = props;
|
|
4503
5082
|
const feelRequiredLabel = ' must be a FEEL expression';
|
|
4504
5083
|
const feelOptionalLabel = ' can optionally be a FEEL expression';
|
|
@@ -4518,7 +5097,7 @@ function FeelIcon(props) {
|
|
|
4518
5097
|
children: feel === 'required' ? jsx(FeelRequiredIcon, {}) : jsx(FeelOptionalIcon, {})
|
|
4519
5098
|
});
|
|
4520
5099
|
}
|
|
4521
|
-
const noop = () => {};
|
|
5100
|
+
const noop$1 = () => {};
|
|
4522
5101
|
function FeelTextfield(props) {
|
|
4523
5102
|
const {
|
|
4524
5103
|
debounce,
|
|
@@ -4675,6 +5254,9 @@ function FeelTextfield(props) {
|
|
|
4675
5254
|
}) : jsx(OptionalComponent, {
|
|
4676
5255
|
...props,
|
|
4677
5256
|
onInput: handleLocalInput,
|
|
5257
|
+
contentAttributes: {
|
|
5258
|
+
'id': prefixId$6(id)
|
|
5259
|
+
},
|
|
4678
5260
|
value: localValue,
|
|
4679
5261
|
ref: editorRef
|
|
4680
5262
|
})]
|
|
@@ -4724,7 +5306,7 @@ const OptionalFeelInput = forwardRef((props, ref) => {
|
|
|
4724
5306
|
value: value || ''
|
|
4725
5307
|
});
|
|
4726
5308
|
});
|
|
4727
|
-
|
|
5309
|
+
forwardRef((props, ref) => {
|
|
4728
5310
|
const {
|
|
4729
5311
|
id,
|
|
4730
5312
|
disabled,
|
|
@@ -4764,17 +5346,24 @@ const OptionalFeelTextArea = forwardRef((props, ref) => {
|
|
|
4764
5346
|
});
|
|
4765
5347
|
});
|
|
4766
5348
|
|
|
4767
|
-
/**
|
|
4768
|
-
* @param {Object} props
|
|
4769
|
-
* @param {Object} props.element
|
|
4770
|
-
* @param {String} props.id
|
|
4771
|
-
* @param {String} props.description
|
|
4772
|
-
* @param {Boolean} props.debounce
|
|
4773
|
-
* @param {Boolean} props.disabled
|
|
4774
|
-
* @param {
|
|
4775
|
-
* @param {
|
|
4776
|
-
* @param {Function} props.
|
|
4777
|
-
* @param {Function} props.
|
|
5349
|
+
/**
|
|
5350
|
+
* @param {Object} props
|
|
5351
|
+
* @param {Object} props.element
|
|
5352
|
+
* @param {String} props.id
|
|
5353
|
+
* @param {String} props.description
|
|
5354
|
+
* @param {Boolean} props.debounce
|
|
5355
|
+
* @param {Boolean} props.disabled
|
|
5356
|
+
* @param {Boolean} props.feel
|
|
5357
|
+
* @param {String} props.label
|
|
5358
|
+
* @param {Function} props.getValue
|
|
5359
|
+
* @param {Function} props.setValue
|
|
5360
|
+
* @param {Function} props.tooltipContainer
|
|
5361
|
+
* @param {Function} props.validate
|
|
5362
|
+
* @param {Function} props.show
|
|
5363
|
+
* @param {Function} props.example
|
|
5364
|
+
* @param {Function} props.variables
|
|
5365
|
+
* @param {Function} props.onFocus
|
|
5366
|
+
* @param {Function} props.onBlur
|
|
4778
5367
|
*/
|
|
4779
5368
|
function FeelEntry(props) {
|
|
4780
5369
|
const {
|
|
@@ -4788,8 +5377,10 @@ function FeelEntry(props) {
|
|
|
4788
5377
|
getValue,
|
|
4789
5378
|
setValue,
|
|
4790
5379
|
tooltipContainer,
|
|
5380
|
+
hostLanguage,
|
|
5381
|
+
singleLine,
|
|
4791
5382
|
validate,
|
|
4792
|
-
show = noop,
|
|
5383
|
+
show = noop$1,
|
|
4793
5384
|
example,
|
|
4794
5385
|
variables,
|
|
4795
5386
|
onFocus,
|
|
@@ -4843,6 +5434,8 @@ function FeelEntry(props) {
|
|
|
4843
5434
|
onFocus: onFocus,
|
|
4844
5435
|
onBlur: onBlur,
|
|
4845
5436
|
example: example,
|
|
5437
|
+
hostLanguage: hostLanguage,
|
|
5438
|
+
singleLine: singleLine,
|
|
4846
5439
|
show: show,
|
|
4847
5440
|
value: value,
|
|
4848
5441
|
variables: variables,
|
|
@@ -4859,28 +5452,35 @@ function FeelEntry(props) {
|
|
|
4859
5452
|
});
|
|
4860
5453
|
}
|
|
4861
5454
|
|
|
4862
|
-
/**
|
|
4863
|
-
* @param {Object} props
|
|
4864
|
-
* @param {Object} props.element
|
|
4865
|
-
* @param {String} props.id
|
|
4866
|
-
* @param {String} props.description
|
|
4867
|
-
* @param {
|
|
4868
|
-
* @param {Boolean} props.
|
|
4869
|
-
* @param {
|
|
4870
|
-
* @param {
|
|
4871
|
-
* @param {
|
|
4872
|
-
* @param {
|
|
4873
|
-
* @param {Function} props.
|
|
4874
|
-
* @param {Function} props.
|
|
5455
|
+
/**
|
|
5456
|
+
* @param {Object} props
|
|
5457
|
+
* @param {Object} props.element
|
|
5458
|
+
* @param {String} props.id
|
|
5459
|
+
* @param {String} props.description
|
|
5460
|
+
* @param {String} props.hostLanguage
|
|
5461
|
+
* @param {Boolean} props.singleLine
|
|
5462
|
+
* @param {Boolean} props.debounce
|
|
5463
|
+
* @param {Boolean} props.disabled
|
|
5464
|
+
* @param {Boolean} props.feel
|
|
5465
|
+
* @param {String} props.label
|
|
5466
|
+
* @param {Function} props.getValue
|
|
5467
|
+
* @param {Function} props.setValue
|
|
5468
|
+
* @param {Function} props.tooltipContainer
|
|
5469
|
+
* @param {Function} props.validate
|
|
5470
|
+
* @param {Function} props.show
|
|
5471
|
+
* @param {Function} props.example
|
|
5472
|
+
* @param {Function} props.variables
|
|
5473
|
+
* @param {Function} props.onFocus
|
|
5474
|
+
* @param {Function} props.onBlur
|
|
4875
5475
|
*/
|
|
4876
|
-
function
|
|
5476
|
+
function FeelTemplatingEntry(props) {
|
|
4877
5477
|
return jsx(FeelEntry, {
|
|
4878
|
-
class: "bio-properties-panel-feel-
|
|
4879
|
-
OptionalComponent:
|
|
5478
|
+
class: "bio-properties-panel-feel-templating",
|
|
5479
|
+
OptionalComponent: CodeEditor$1,
|
|
4880
5480
|
...props
|
|
4881
5481
|
});
|
|
4882
5482
|
}
|
|
4883
|
-
function isEdited$
|
|
5483
|
+
function isEdited$7(node) {
|
|
4884
5484
|
return node && (!!node.value || node.classList.contains('edited'));
|
|
4885
5485
|
}
|
|
4886
5486
|
|
|
@@ -4950,22 +5550,22 @@ function NumberField(props) {
|
|
|
4950
5550
|
});
|
|
4951
5551
|
}
|
|
4952
5552
|
|
|
4953
|
-
/**
|
|
4954
|
-
* @param {Object} props
|
|
4955
|
-
* @param {Boolean} props.debounce
|
|
4956
|
-
* @param {String} props.description
|
|
4957
|
-
* @param {Boolean} props.disabled
|
|
4958
|
-
* @param {Object} props.element
|
|
4959
|
-
* @param {Function} props.getValue
|
|
4960
|
-
* @param {String} props.id
|
|
4961
|
-
* @param {String} props.label
|
|
4962
|
-
* @param {String} props.max
|
|
4963
|
-
* @param {String} props.min
|
|
4964
|
-
* @param {Function} props.setValue
|
|
4965
|
-
* @param {Function} props.onFocus
|
|
4966
|
-
* @param {Function} props.onBlur
|
|
4967
|
-
* @param {String} props.step
|
|
4968
|
-
* @param {Function} props.validate
|
|
5553
|
+
/**
|
|
5554
|
+
* @param {Object} props
|
|
5555
|
+
* @param {Boolean} props.debounce
|
|
5556
|
+
* @param {String} props.description
|
|
5557
|
+
* @param {Boolean} props.disabled
|
|
5558
|
+
* @param {Object} props.element
|
|
5559
|
+
* @param {Function} props.getValue
|
|
5560
|
+
* @param {String} props.id
|
|
5561
|
+
* @param {String} props.label
|
|
5562
|
+
* @param {String} props.max
|
|
5563
|
+
* @param {String} props.min
|
|
5564
|
+
* @param {Function} props.setValue
|
|
5565
|
+
* @param {Function} props.onFocus
|
|
5566
|
+
* @param {Function} props.onBlur
|
|
5567
|
+
* @param {String} props.step
|
|
5568
|
+
* @param {Function} props.validate
|
|
4969
5569
|
*/
|
|
4970
5570
|
function NumberFieldEntry(props) {
|
|
4971
5571
|
const {
|
|
@@ -5090,6 +5690,16 @@ function Select(props) {
|
|
|
5090
5690
|
value: localValue,
|
|
5091
5691
|
disabled: disabled,
|
|
5092
5692
|
children: options.map((option, idx) => {
|
|
5693
|
+
if (option.children) {
|
|
5694
|
+
return jsx("optgroup", {
|
|
5695
|
+
label: option.label,
|
|
5696
|
+
children: option.children.map((child, idx) => jsx("option", {
|
|
5697
|
+
value: child.value,
|
|
5698
|
+
disabled: child.disabled,
|
|
5699
|
+
children: child.label
|
|
5700
|
+
}, idx))
|
|
5701
|
+
}, idx);
|
|
5702
|
+
}
|
|
5093
5703
|
return jsx("option", {
|
|
5094
5704
|
value: option.value,
|
|
5095
5705
|
disabled: option.disabled,
|
|
@@ -5100,18 +5710,19 @@ function Select(props) {
|
|
|
5100
5710
|
});
|
|
5101
5711
|
}
|
|
5102
5712
|
|
|
5103
|
-
/**
|
|
5104
|
-
* @param {object} props
|
|
5105
|
-
* @param {object} props.element
|
|
5106
|
-
* @param {string} props.id
|
|
5107
|
-
* @param {string} [props.description]
|
|
5108
|
-
* @param {string} props.label
|
|
5109
|
-
* @param {Function} props.getValue
|
|
5110
|
-
* @param {Function} props.setValue
|
|
5111
|
-
* @param {Function} props.onFocus
|
|
5112
|
-
* @param {Function} props.onBlur
|
|
5113
|
-
* @param {Function} props.getOptions
|
|
5114
|
-
* @param {boolean} [props.disabled]
|
|
5713
|
+
/**
|
|
5714
|
+
* @param {object} props
|
|
5715
|
+
* @param {object} props.element
|
|
5716
|
+
* @param {string} props.id
|
|
5717
|
+
* @param {string} [props.description]
|
|
5718
|
+
* @param {string} props.label
|
|
5719
|
+
* @param {Function} props.getValue
|
|
5720
|
+
* @param {Function} props.setValue
|
|
5721
|
+
* @param {Function} props.onFocus
|
|
5722
|
+
* @param {Function} props.onBlur
|
|
5723
|
+
* @param {Function} props.getOptions
|
|
5724
|
+
* @param {boolean} [props.disabled]
|
|
5725
|
+
* @param {Function} [props.validate]
|
|
5115
5726
|
*/
|
|
5116
5727
|
function SelectEntry(props) {
|
|
5117
5728
|
const {
|
|
@@ -5124,11 +5735,37 @@ function SelectEntry(props) {
|
|
|
5124
5735
|
getOptions,
|
|
5125
5736
|
disabled,
|
|
5126
5737
|
onFocus,
|
|
5127
|
-
onBlur
|
|
5738
|
+
onBlur,
|
|
5739
|
+
validate
|
|
5128
5740
|
} = props;
|
|
5129
|
-
const value = getValue(element);
|
|
5130
5741
|
const options = getOptions(element);
|
|
5131
|
-
const
|
|
5742
|
+
const [cachedInvalidValue, setCachedInvalidValue] = useState(null);
|
|
5743
|
+
const globalError = useError(id);
|
|
5744
|
+
const [localError, setLocalError] = useState(null);
|
|
5745
|
+
let value = getValue(element);
|
|
5746
|
+
const previousValue = usePrevious(value);
|
|
5747
|
+
useEffect(() => {
|
|
5748
|
+
if (isFunction(validate)) {
|
|
5749
|
+
const newValidationError = validate(value) || null;
|
|
5750
|
+
setLocalError(newValidationError);
|
|
5751
|
+
}
|
|
5752
|
+
}, [value]);
|
|
5753
|
+
const onChange = newValue => {
|
|
5754
|
+
let newValidationError = null;
|
|
5755
|
+
if (isFunction(validate)) {
|
|
5756
|
+
newValidationError = validate(newValue) || null;
|
|
5757
|
+
}
|
|
5758
|
+
if (newValidationError) {
|
|
5759
|
+
setCachedInvalidValue(newValue);
|
|
5760
|
+
} else {
|
|
5761
|
+
setValue(newValue);
|
|
5762
|
+
}
|
|
5763
|
+
setLocalError(newValidationError);
|
|
5764
|
+
};
|
|
5765
|
+
if (previousValue === value && localError) {
|
|
5766
|
+
value = cachedInvalidValue;
|
|
5767
|
+
}
|
|
5768
|
+
const error = globalError || localError;
|
|
5132
5769
|
return jsxs("div", {
|
|
5133
5770
|
class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
|
|
5134
5771
|
"data-entry-id": id,
|
|
@@ -5136,7 +5773,7 @@ function SelectEntry(props) {
|
|
|
5136
5773
|
id: id,
|
|
5137
5774
|
label: label,
|
|
5138
5775
|
value: value,
|
|
5139
|
-
onChange:
|
|
5776
|
+
onChange: onChange,
|
|
5140
5777
|
onFocus: onFocus,
|
|
5141
5778
|
onBlur: onBlur,
|
|
5142
5779
|
options: options,
|
|
@@ -5160,18 +5797,26 @@ function isEdited$4(node) {
|
|
|
5160
5797
|
function prefixId$4(id) {
|
|
5161
5798
|
return `bio-properties-panel-${id}`;
|
|
5162
5799
|
}
|
|
5800
|
+
function resizeToContents(element) {
|
|
5801
|
+
element.style.height = 'auto';
|
|
5802
|
+
|
|
5803
|
+
// a 2px pixel offset is required to prevent scrollbar from
|
|
5804
|
+
// appearing on OS with a full length scroll bar (Windows/Linux)
|
|
5805
|
+
element.style.height = `${element.scrollHeight + 2}px`;
|
|
5806
|
+
}
|
|
5163
5807
|
function TextArea(props) {
|
|
5164
5808
|
const {
|
|
5165
5809
|
id,
|
|
5166
5810
|
label,
|
|
5167
|
-
rows = 2,
|
|
5168
5811
|
debounce,
|
|
5169
5812
|
onInput,
|
|
5170
5813
|
value = '',
|
|
5171
5814
|
disabled,
|
|
5172
5815
|
monospace,
|
|
5173
5816
|
onFocus,
|
|
5174
|
-
onBlur
|
|
5817
|
+
onBlur,
|
|
5818
|
+
autoResize,
|
|
5819
|
+
rows = autoResize ? 1 : 2
|
|
5175
5820
|
} = props;
|
|
5176
5821
|
const [localValue, setLocalValue] = useState(value);
|
|
5177
5822
|
const ref = useShowEntryEvent(id);
|
|
@@ -5182,8 +5827,12 @@ function TextArea(props) {
|
|
|
5182
5827
|
}, [onInput, debounce]);
|
|
5183
5828
|
const handleInput = e => {
|
|
5184
5829
|
handleInputCallback(e);
|
|
5830
|
+
autoResize && resizeToContents(e.target);
|
|
5185
5831
|
setLocalValue(e.target.value);
|
|
5186
5832
|
};
|
|
5833
|
+
useLayoutEffect(() => {
|
|
5834
|
+
autoResize && resizeToContents(ref.current);
|
|
5835
|
+
}, []);
|
|
5187
5836
|
useEffect(() => {
|
|
5188
5837
|
if (value === localValue) {
|
|
5189
5838
|
return;
|
|
@@ -5201,7 +5850,7 @@ function TextArea(props) {
|
|
|
5201
5850
|
id: prefixId$2(id),
|
|
5202
5851
|
name: id,
|
|
5203
5852
|
spellCheck: "false",
|
|
5204
|
-
class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : ''),
|
|
5853
|
+
class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
|
|
5205
5854
|
onInput: handleInput,
|
|
5206
5855
|
onFocus: onFocus,
|
|
5207
5856
|
onBlur: onBlur,
|
|
@@ -5213,20 +5862,20 @@ function TextArea(props) {
|
|
|
5213
5862
|
});
|
|
5214
5863
|
}
|
|
5215
5864
|
|
|
5216
|
-
/**
|
|
5217
|
-
* @param {object} props
|
|
5218
|
-
* @param {object} props.element
|
|
5219
|
-
* @param {string} props.id
|
|
5220
|
-
* @param {string} props.description
|
|
5221
|
-
* @param {boolean} props.debounce
|
|
5222
|
-
* @param {string} props.label
|
|
5223
|
-
* @param {Function} props.getValue
|
|
5224
|
-
* @param {Function} props.setValue
|
|
5225
|
-
* @param {Function} props.onFocus
|
|
5226
|
-
* @param {Function} props.onBlur
|
|
5227
|
-
* @param {number} props.rows
|
|
5228
|
-
* @param {boolean} props.monospace
|
|
5229
|
-
* @param {boolean} [props.disabled]
|
|
5865
|
+
/**
|
|
5866
|
+
* @param {object} props
|
|
5867
|
+
* @param {object} props.element
|
|
5868
|
+
* @param {string} props.id
|
|
5869
|
+
* @param {string} props.description
|
|
5870
|
+
* @param {boolean} props.debounce
|
|
5871
|
+
* @param {string} props.label
|
|
5872
|
+
* @param {Function} props.getValue
|
|
5873
|
+
* @param {Function} props.setValue
|
|
5874
|
+
* @param {Function} props.onFocus
|
|
5875
|
+
* @param {Function} props.onBlur
|
|
5876
|
+
* @param {number} props.rows
|
|
5877
|
+
* @param {boolean} props.monospace
|
|
5878
|
+
* @param {boolean} [props.disabled]
|
|
5230
5879
|
*/
|
|
5231
5880
|
function TextAreaEntry(props) {
|
|
5232
5881
|
const {
|
|
@@ -5241,7 +5890,8 @@ function TextAreaEntry(props) {
|
|
|
5241
5890
|
monospace,
|
|
5242
5891
|
disabled,
|
|
5243
5892
|
onFocus,
|
|
5244
|
-
onBlur
|
|
5893
|
+
onBlur,
|
|
5894
|
+
autoResize
|
|
5245
5895
|
} = props;
|
|
5246
5896
|
const value = getValue(element);
|
|
5247
5897
|
const error = useError(id);
|
|
@@ -5258,7 +5908,8 @@ function TextAreaEntry(props) {
|
|
|
5258
5908
|
rows: rows,
|
|
5259
5909
|
debounce: debounce,
|
|
5260
5910
|
monospace: monospace,
|
|
5261
|
-
disabled: disabled
|
|
5911
|
+
disabled: disabled,
|
|
5912
|
+
autoResize: autoResize
|
|
5262
5913
|
}, element), error && jsx("div", {
|
|
5263
5914
|
class: "bio-properties-panel-error",
|
|
5264
5915
|
children: error
|
|
@@ -5329,19 +5980,19 @@ function Textfield(props) {
|
|
|
5329
5980
|
});
|
|
5330
5981
|
}
|
|
5331
5982
|
|
|
5332
|
-
/**
|
|
5333
|
-
* @param {Object} props
|
|
5334
|
-
* @param {Object} props.element
|
|
5335
|
-
* @param {String} props.id
|
|
5336
|
-
* @param {String} props.description
|
|
5337
|
-
* @param {Boolean} props.debounce
|
|
5338
|
-
* @param {Boolean} props.disabled
|
|
5339
|
-
* @param {String} props.label
|
|
5340
|
-
* @param {Function} props.getValue
|
|
5341
|
-
* @param {Function} props.setValue
|
|
5342
|
-
* @param {Function} props.onFocus
|
|
5343
|
-
* @param {Function} props.onBlur
|
|
5344
|
-
* @param {Function} props.validate
|
|
5983
|
+
/**
|
|
5984
|
+
* @param {Object} props
|
|
5985
|
+
* @param {Object} props.element
|
|
5986
|
+
* @param {String} props.id
|
|
5987
|
+
* @param {String} props.description
|
|
5988
|
+
* @param {Boolean} props.debounce
|
|
5989
|
+
* @param {Boolean} props.disabled
|
|
5990
|
+
* @param {String} props.label
|
|
5991
|
+
* @param {Function} props.getValue
|
|
5992
|
+
* @param {Function} props.setValue
|
|
5993
|
+
* @param {Function} props.onFocus
|
|
5994
|
+
* @param {Function} props.onBlur
|
|
5995
|
+
* @param {Function} props.validate
|
|
5345
5996
|
*/
|
|
5346
5997
|
function TextfieldEntry(props) {
|
|
5347
5998
|
const {
|
|
@@ -5608,7 +6259,7 @@ function AltTextEntry(props) {
|
|
|
5608
6259
|
component: AltText,
|
|
5609
6260
|
editField: editField,
|
|
5610
6261
|
field: field,
|
|
5611
|
-
isEdited: isEdited$
|
|
6262
|
+
isEdited: isEdited$7
|
|
5612
6263
|
});
|
|
5613
6264
|
}
|
|
5614
6265
|
return entries;
|
|
@@ -5642,59 +6293,70 @@ function AltText(props) {
|
|
|
5642
6293
|
});
|
|
5643
6294
|
}
|
|
5644
6295
|
|
|
6296
|
+
const AUTO_OPTION_VALUE = '';
|
|
5645
6297
|
function ColumnsEntry(props) {
|
|
5646
6298
|
const {
|
|
5647
6299
|
editField,
|
|
5648
6300
|
field
|
|
5649
6301
|
} = props;
|
|
5650
|
-
const {
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
component: Columns,
|
|
5658
|
-
editField: editField,
|
|
5659
|
-
field: field,
|
|
5660
|
-
isEdited: isEdited$5
|
|
5661
|
-
});
|
|
5662
|
-
}
|
|
6302
|
+
const entries = [{
|
|
6303
|
+
id: 'columns',
|
|
6304
|
+
component: Columns,
|
|
6305
|
+
field,
|
|
6306
|
+
editField,
|
|
6307
|
+
isEdited: isEdited$4
|
|
6308
|
+
}];
|
|
5663
6309
|
return entries;
|
|
5664
6310
|
}
|
|
5665
6311
|
function Columns(props) {
|
|
5666
6312
|
const {
|
|
5667
|
-
editField,
|
|
5668
6313
|
field,
|
|
6314
|
+
editField,
|
|
5669
6315
|
id
|
|
5670
6316
|
} = props;
|
|
5671
6317
|
const debounce = useService('debounce');
|
|
5672
|
-
const
|
|
5673
|
-
|
|
6318
|
+
const formLayoutValidator = useService('formLayoutValidator');
|
|
6319
|
+
const validate = value => {
|
|
6320
|
+
return formLayoutValidator.validateField(field, value ? parseInt(value) : null);
|
|
5674
6321
|
};
|
|
5675
6322
|
const setValue = value => {
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
components.push(Default.create({
|
|
5680
|
-
_parent: field.id
|
|
5681
|
-
}));
|
|
5682
|
-
}
|
|
5683
|
-
} else {
|
|
5684
|
-
components = components.slice(0, value);
|
|
5685
|
-
}
|
|
5686
|
-
editField(field, 'components', components);
|
|
6323
|
+
const layout = get(field, ['layout'], {});
|
|
6324
|
+
const newValue = value ? parseInt(value) : null;
|
|
6325
|
+
editField(field, ['layout'], set$1(layout, ['columns'], newValue));
|
|
5687
6326
|
};
|
|
5688
|
-
|
|
6327
|
+
const getValue = () => {
|
|
6328
|
+
return get(field, ['layout', 'columns']);
|
|
6329
|
+
};
|
|
6330
|
+
const getOptions = () => {
|
|
6331
|
+
return [{
|
|
6332
|
+
label: 'Auto',
|
|
6333
|
+
value: AUTO_OPTION_VALUE
|
|
6334
|
+
},
|
|
6335
|
+
// todo(pinussilvestrus): make options dependant on field type
|
|
6336
|
+
// cf. https://github.com/bpmn-io/form-js/issues/575
|
|
6337
|
+
...[2, 4, 6, 8, 10, 12, 14, 16].map(asOption)];
|
|
6338
|
+
};
|
|
6339
|
+
return SelectEntry({
|
|
5689
6340
|
debounce,
|
|
5690
6341
|
element: field,
|
|
5691
|
-
getValue,
|
|
5692
6342
|
id,
|
|
5693
6343
|
label: 'Columns',
|
|
5694
|
-
|
|
6344
|
+
getOptions,
|
|
6345
|
+
getValue,
|
|
6346
|
+
setValue,
|
|
6347
|
+
validate
|
|
5695
6348
|
});
|
|
5696
6349
|
}
|
|
5697
6350
|
|
|
6351
|
+
// helper /////////
|
|
6352
|
+
|
|
6353
|
+
function asOption(number) {
|
|
6354
|
+
return {
|
|
6355
|
+
value: number,
|
|
6356
|
+
label: number.toString()
|
|
6357
|
+
};
|
|
6358
|
+
}
|
|
6359
|
+
|
|
5698
6360
|
function DescriptionEntry(props) {
|
|
5699
6361
|
const {
|
|
5700
6362
|
editField,
|
|
@@ -5989,7 +6651,7 @@ function DisabledEntry(props) {
|
|
|
5989
6651
|
component: Disabled,
|
|
5990
6652
|
editField: editField,
|
|
5991
6653
|
field: field,
|
|
5992
|
-
isEdited: isEdited$
|
|
6654
|
+
isEdited: isEdited$8
|
|
5993
6655
|
});
|
|
5994
6656
|
}
|
|
5995
6657
|
return entries;
|
|
@@ -6199,6 +6861,7 @@ function simpleBoolEntryFactory(options) {
|
|
|
6199
6861
|
const {
|
|
6200
6862
|
id,
|
|
6201
6863
|
label,
|
|
6864
|
+
description,
|
|
6202
6865
|
path,
|
|
6203
6866
|
props
|
|
6204
6867
|
} = options;
|
|
@@ -6212,8 +6875,9 @@ function simpleBoolEntryFactory(options) {
|
|
|
6212
6875
|
path,
|
|
6213
6876
|
field,
|
|
6214
6877
|
editField,
|
|
6878
|
+
description,
|
|
6215
6879
|
component: SimpleBoolComponent,
|
|
6216
|
-
isEdited: isEdited$
|
|
6880
|
+
isEdited: isEdited$8
|
|
6217
6881
|
};
|
|
6218
6882
|
}
|
|
6219
6883
|
const SimpleBoolComponent = props => {
|
|
@@ -6222,7 +6886,8 @@ const SimpleBoolComponent = props => {
|
|
|
6222
6886
|
label,
|
|
6223
6887
|
path,
|
|
6224
6888
|
field,
|
|
6225
|
-
editField
|
|
6889
|
+
editField,
|
|
6890
|
+
description
|
|
6226
6891
|
} = props;
|
|
6227
6892
|
const getValue = () => get(field, path, '');
|
|
6228
6893
|
const setValue = value => editField(field, path, value);
|
|
@@ -6231,7 +6896,8 @@ const SimpleBoolComponent = props => {
|
|
|
6231
6896
|
getValue,
|
|
6232
6897
|
id,
|
|
6233
6898
|
label,
|
|
6234
|
-
setValue
|
|
6899
|
+
setValue,
|
|
6900
|
+
description
|
|
6235
6901
|
});
|
|
6236
6902
|
};
|
|
6237
6903
|
|
|
@@ -6287,7 +6953,7 @@ function SourceEntry(props) {
|
|
|
6287
6953
|
component: Source,
|
|
6288
6954
|
editField: editField,
|
|
6289
6955
|
field: field,
|
|
6290
|
-
isEdited: isEdited$
|
|
6956
|
+
isEdited: isEdited$7
|
|
6291
6957
|
});
|
|
6292
6958
|
}
|
|
6293
6959
|
return entries;
|
|
@@ -6325,21 +6991,38 @@ function Source(props) {
|
|
|
6325
6991
|
function TextEntry(props) {
|
|
6326
6992
|
const {
|
|
6327
6993
|
editField,
|
|
6994
|
+
/* getService, */
|
|
6328
6995
|
field
|
|
6329
6996
|
} = props;
|
|
6330
6997
|
const {
|
|
6331
6998
|
type
|
|
6332
6999
|
} = field;
|
|
7000
|
+
|
|
7001
|
+
// const templating = getService('templating');
|
|
7002
|
+
|
|
6333
7003
|
if (type !== 'text') {
|
|
6334
7004
|
return [];
|
|
6335
7005
|
}
|
|
6336
|
-
|
|
7006
|
+
const entries = [{
|
|
6337
7007
|
id: 'text',
|
|
6338
7008
|
component: Text,
|
|
6339
7009
|
editField: editField,
|
|
6340
7010
|
field: field,
|
|
6341
|
-
isEdited: isEdited$
|
|
7011
|
+
isEdited: isEdited$7
|
|
6342
7012
|
}];
|
|
7013
|
+
|
|
7014
|
+
// todo: skipped to make the release without too much risk
|
|
7015
|
+
// if (templating.isTemplate(field.text)) {
|
|
7016
|
+
// entries.push(simpleBoolEntryFactory({
|
|
7017
|
+
// id: 'strict',
|
|
7018
|
+
// path: [ 'strict' ],
|
|
7019
|
+
// label: 'Strict templating',
|
|
7020
|
+
// description: 'Enforces types to be correct',
|
|
7021
|
+
// props
|
|
7022
|
+
// }));
|
|
7023
|
+
// }
|
|
7024
|
+
|
|
7025
|
+
return entries;
|
|
6343
7026
|
}
|
|
6344
7027
|
function Text(props) {
|
|
6345
7028
|
const {
|
|
@@ -6358,15 +7041,21 @@ function Text(props) {
|
|
|
6358
7041
|
const setValue = value => {
|
|
6359
7042
|
return editField(field, path, value);
|
|
6360
7043
|
};
|
|
6361
|
-
|
|
7044
|
+
const description = useMemo(() => jsxs(Fragment, {
|
|
7045
|
+
children: ["Supports markdown and templating. ", jsx("a", {
|
|
7046
|
+
href: "https://docs.camunda.io/docs/components/modeler/forms/form-element-library/forms-element-library-text/",
|
|
7047
|
+
target: "_blank",
|
|
7048
|
+
children: "Learn more"
|
|
7049
|
+
})]
|
|
7050
|
+
}), []);
|
|
7051
|
+
return FeelTemplatingEntry({
|
|
6362
7052
|
debounce,
|
|
6363
|
-
description
|
|
7053
|
+
description,
|
|
6364
7054
|
element: field,
|
|
6365
|
-
feel: 'optional',
|
|
6366
7055
|
getValue,
|
|
6367
7056
|
id,
|
|
6368
7057
|
label: 'Text',
|
|
6369
|
-
|
|
7058
|
+
hostLanguage: 'markdown',
|
|
6370
7059
|
setValue,
|
|
6371
7060
|
variables
|
|
6372
7061
|
});
|
|
@@ -6482,7 +7171,7 @@ function NumberSerializationEntry(props) {
|
|
|
6482
7171
|
entries.push({
|
|
6483
7172
|
id: 'serialize-to-string',
|
|
6484
7173
|
component: SerializeToString,
|
|
6485
|
-
isEdited: isEdited$
|
|
7174
|
+
isEdited: isEdited$8,
|
|
6486
7175
|
editField,
|
|
6487
7176
|
field
|
|
6488
7177
|
});
|
|
@@ -6541,7 +7230,7 @@ function DateTimeEntry(props) {
|
|
|
6541
7230
|
entries.push({
|
|
6542
7231
|
id: 'use24h',
|
|
6543
7232
|
component: Use24h,
|
|
6544
|
-
isEdited: isEdited$
|
|
7233
|
+
isEdited: isEdited$8,
|
|
6545
7234
|
editField,
|
|
6546
7235
|
field
|
|
6547
7236
|
});
|
|
@@ -6654,7 +7343,7 @@ function DateTimeConstraintsEntry(props) {
|
|
|
6654
7343
|
entries.push({
|
|
6655
7344
|
id: id + '-disallowPassedDates',
|
|
6656
7345
|
component: DisallowPassedDates,
|
|
6657
|
-
isEdited: isEdited$
|
|
7346
|
+
isEdited: isEdited$8,
|
|
6658
7347
|
editField,
|
|
6659
7348
|
field
|
|
6660
7349
|
});
|
|
@@ -7029,11 +7718,19 @@ function InputKeyValuesSourceEntry(props) {
|
|
|
7029
7718
|
field,
|
|
7030
7719
|
id
|
|
7031
7720
|
} = props;
|
|
7721
|
+
const schema = '[\n {\n "label": "dollar",\n "value": "$"\n }\n]';
|
|
7722
|
+
const description = jsxs("div", {
|
|
7723
|
+
children: ["Define which input property to populate the values from.", jsx("br", {}), jsx("br", {}), "The input property may be an array of simple values or alternatively follow this schema:", jsx("pre", {
|
|
7724
|
+
children: jsx("code", {
|
|
7725
|
+
children: schema
|
|
7726
|
+
})
|
|
7727
|
+
})]
|
|
7728
|
+
});
|
|
7032
7729
|
return [{
|
|
7033
7730
|
id: id + '-key',
|
|
7034
7731
|
component: InputValuesKey,
|
|
7035
7732
|
label: 'Input values key',
|
|
7036
|
-
description
|
|
7733
|
+
description,
|
|
7037
7734
|
isEdited: isEdited$1,
|
|
7038
7735
|
editField,
|
|
7039
7736
|
field
|
|
@@ -7228,7 +7925,7 @@ function ConditionEntry(props) {
|
|
|
7228
7925
|
component: Condition,
|
|
7229
7926
|
editField: editField,
|
|
7230
7927
|
field: field,
|
|
7231
|
-
isEdited: isEdited$
|
|
7928
|
+
isEdited: isEdited$7
|
|
7232
7929
|
}];
|
|
7233
7930
|
}
|
|
7234
7931
|
function Condition(props) {
|
|
@@ -7266,7 +7963,7 @@ function Condition(props) {
|
|
|
7266
7963
|
});
|
|
7267
7964
|
}
|
|
7268
7965
|
|
|
7269
|
-
function GeneralGroup(field, editField) {
|
|
7966
|
+
function GeneralGroup(field, editField, getService) {
|
|
7270
7967
|
const entries = [...IdEntry({
|
|
7271
7968
|
field,
|
|
7272
7969
|
editField
|
|
@@ -7285,15 +7982,13 @@ function GeneralGroup(field, editField) {
|
|
|
7285
7982
|
}), ...ActionEntry({
|
|
7286
7983
|
field,
|
|
7287
7984
|
editField
|
|
7288
|
-
}), ...ColumnsEntry({
|
|
7289
|
-
field,
|
|
7290
|
-
editField
|
|
7291
7985
|
}), ...DateTimeEntry({
|
|
7292
7986
|
field,
|
|
7293
7987
|
editField
|
|
7294
7988
|
}), ...TextEntry({
|
|
7295
7989
|
field,
|
|
7296
|
-
editField
|
|
7990
|
+
editField,
|
|
7991
|
+
getService
|
|
7297
7992
|
}), ...NumberEntries({
|
|
7298
7993
|
field,
|
|
7299
7994
|
editField
|
|
@@ -7389,7 +8084,7 @@ function ValidationGroup(field, editField) {
|
|
|
7389
8084
|
component: Required,
|
|
7390
8085
|
getValue,
|
|
7391
8086
|
field,
|
|
7392
|
-
isEdited: isEdited$
|
|
8087
|
+
isEdited: isEdited$8,
|
|
7393
8088
|
onChange
|
|
7394
8089
|
}];
|
|
7395
8090
|
if (type === 'textfield') {
|
|
@@ -7731,6 +8426,27 @@ function AppearanceGroup(field, editField) {
|
|
|
7731
8426
|
};
|
|
7732
8427
|
}
|
|
7733
8428
|
|
|
8429
|
+
function LayoutGroup(field, editField) {
|
|
8430
|
+
const {
|
|
8431
|
+
type
|
|
8432
|
+
} = field;
|
|
8433
|
+
if (type === 'default') {
|
|
8434
|
+
return null;
|
|
8435
|
+
}
|
|
8436
|
+
const entries = [...ColumnsEntry({
|
|
8437
|
+
field,
|
|
8438
|
+
editField
|
|
8439
|
+
})];
|
|
8440
|
+
if (entries.length === 0) {
|
|
8441
|
+
return null;
|
|
8442
|
+
}
|
|
8443
|
+
return {
|
|
8444
|
+
id: 'layout',
|
|
8445
|
+
label: 'Layout',
|
|
8446
|
+
entries
|
|
8447
|
+
};
|
|
8448
|
+
}
|
|
8449
|
+
|
|
7734
8450
|
function ConditionGroup(field, editField) {
|
|
7735
8451
|
const {
|
|
7736
8452
|
type
|
|
@@ -7749,11 +8465,11 @@ function ConditionGroup(field, editField) {
|
|
|
7749
8465
|
};
|
|
7750
8466
|
}
|
|
7751
8467
|
|
|
7752
|
-
function getGroups(field, editField) {
|
|
8468
|
+
function getGroups(field, editField, getService) {
|
|
7753
8469
|
if (!field) {
|
|
7754
8470
|
return [];
|
|
7755
8471
|
}
|
|
7756
|
-
const groups = [GeneralGroup(field, editField), ConditionGroup(field, editField), AppearanceGroup(field, editField), SerializationGroup(field, editField), ...ValuesGroups(field, editField), ConstraintsGroup(field, editField), ValidationGroup(field, editField), CustomValuesGroup(field, editField)];
|
|
8472
|
+
const groups = [GeneralGroup(field, editField, getService), ConditionGroup(field, editField), LayoutGroup(field, editField), AppearanceGroup(field, editField), SerializationGroup(field, editField), ...ValuesGroups(field, editField), ConstraintsGroup(field, editField), ValidationGroup(field, editField), CustomValuesGroup(field, editField)];
|
|
7757
8473
|
|
|
7758
8474
|
// contract: if a group returns null, it should not be displayed at all
|
|
7759
8475
|
return groups.filter(group => group !== null);
|
|
@@ -7806,10 +8522,9 @@ function FormPropertiesPanel(props) {
|
|
|
7806
8522
|
};
|
|
7807
8523
|
}, []);
|
|
7808
8524
|
const selectedFormField = state.selectedFormField;
|
|
8525
|
+
const getService = (type, strict = true) => injector.get(type, strict);
|
|
7809
8526
|
const propertiesPanelContext = {
|
|
7810
|
-
getService
|
|
7811
|
-
return injector.get(type, strict);
|
|
7812
|
-
}
|
|
8527
|
+
getService
|
|
7813
8528
|
};
|
|
7814
8529
|
const onFocus = () => eventBus.fire('propertiesPanel.focusin');
|
|
7815
8530
|
const onBlur = () => eventBus.fire('propertiesPanel.focusout');
|
|
@@ -7824,7 +8539,7 @@ function FormPropertiesPanel(props) {
|
|
|
7824
8539
|
children: jsx(PropertiesPanel, {
|
|
7825
8540
|
element: selectedFormField,
|
|
7826
8541
|
eventBus: eventBus,
|
|
7827
|
-
groups: getGroups(selectedFormField, editField),
|
|
8542
|
+
groups: getGroups(selectedFormField, editField, getService),
|
|
7828
8543
|
headerProvider: PropertiesPanelHeaderProvider,
|
|
7829
8544
|
placeholderProvider: PropertiesPanelPlaceholderProvider
|
|
7830
8545
|
})
|
|
@@ -7902,6 +8617,12 @@ var PropertiesPanelModule = {
|
|
|
7902
8617
|
propertiesPanel: ['type', PropertiesPanelRenderer]
|
|
7903
8618
|
};
|
|
7904
8619
|
|
|
8620
|
+
var ExpressionLanguageModule = {
|
|
8621
|
+
__init__: ['expressionLanguage', 'templating'],
|
|
8622
|
+
expressionLanguage: ['type', FeelExpressionLanguage],
|
|
8623
|
+
templating: ['type', FeelersTemplating]
|
|
8624
|
+
};
|
|
8625
|
+
|
|
7905
8626
|
const ids = new Ids([32, 36, 1]);
|
|
7906
8627
|
|
|
7907
8628
|
/**
|
|
@@ -8154,7 +8875,7 @@ class FormEditor {
|
|
|
8154
8875
|
* @internal
|
|
8155
8876
|
*/
|
|
8156
8877
|
_getModules() {
|
|
8157
|
-
return [ModelingModule, EditorActionsModule, KeyboardModule, SelectionModule, PaletteModule, PropertiesPanelModule];
|
|
8878
|
+
return [ModelingModule, EditorActionsModule, DraggingModule, KeyboardModule, SelectionModule, PaletteModule, ExpressionLanguageModule, MarkdownModule, PropertiesPanelModule];
|
|
8158
8879
|
}
|
|
8159
8880
|
|
|
8160
8881
|
/**
|