@bpmn-io/form-js-editor 1.3.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +152 -116
  3. package/dist/assets/form-js-editor-base.css +821 -797
  4. package/dist/assets/form-js-editor.css +46 -17
  5. package/dist/assets/properties-panel.css +6 -1
  6. package/dist/index.cjs +1011 -855
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.es.js +1045 -894
  9. package/dist/index.es.js.map +1 -1
  10. package/dist/types/FormEditor.d.ts +1 -0
  11. package/dist/types/features/palette/components/Palette.d.ts +35 -5
  12. package/dist/types/features/palette/components/PaletteEntry.d.ts +1 -0
  13. package/dist/types/features/properties-panel/PropertiesPanelHeaderProvider.d.ts +1 -1
  14. package/dist/types/features/properties-panel/PropertiesPanelRenderer.d.ts +17 -0
  15. package/dist/types/features/properties-panel/PropertiesProvider.d.ts +10 -0
  16. package/dist/types/features/properties-panel/Util.d.ts +2 -0
  17. package/dist/types/features/properties-panel/entries/ActionEntry.d.ts +1 -0
  18. package/dist/types/features/properties-panel/entries/AdornerEntry.d.ts +1 -0
  19. package/dist/types/features/properties-panel/entries/AltTextEntry.d.ts +1 -0
  20. package/dist/types/features/properties-panel/entries/DateTimeConstraintsEntry.d.ts +1 -0
  21. package/dist/types/features/properties-panel/entries/DateTimeEntry.d.ts +1 -0
  22. package/dist/types/features/properties-panel/entries/DateTimeSerializationEntry.d.ts +1 -0
  23. package/dist/types/features/properties-panel/entries/DefaultValueEntry.d.ts +11 -1
  24. package/dist/types/features/properties-panel/entries/DescriptionEntry.d.ts +1 -0
  25. package/dist/types/features/properties-panel/entries/DisabledEntry.d.ts +1 -0
  26. package/dist/types/features/properties-panel/entries/GroupEntries.d.ts +1 -0
  27. package/dist/types/features/properties-panel/entries/IdEntry.d.ts +1 -0
  28. package/dist/types/features/properties-panel/entries/ImageSourceEntry.d.ts +1 -0
  29. package/dist/types/features/properties-panel/entries/KeyEntry.d.ts +1 -0
  30. package/dist/types/features/properties-panel/entries/LabelEntry.d.ts +1 -0
  31. package/dist/types/features/properties-panel/entries/NumberEntries.d.ts +1 -0
  32. package/dist/types/features/properties-panel/entries/NumberSerializationEntry.d.ts +1 -0
  33. package/dist/types/features/properties-panel/entries/ReadonlyEntry.d.ts +1 -0
  34. package/dist/types/features/properties-panel/entries/SelectEntries.d.ts +1 -0
  35. package/dist/types/features/properties-panel/entries/SpacerEntry.d.ts +1 -0
  36. package/dist/types/features/properties-panel/entries/TextEntry.d.ts +1 -0
  37. package/dist/types/features/properties-panel/entries/factories/simpleBoolEntryFactory.d.ts +1 -0
  38. package/dist/types/features/properties-panel/groups/AppearanceGroup.d.ts +1 -0
  39. package/dist/types/features/properties-panel/groups/ConstraintsGroup.d.ts +1 -0
  40. package/dist/types/features/properties-panel/groups/GeneralGroup.d.ts +17 -1
  41. package/dist/types/features/properties-panel/groups/SerializationGroup.d.ts +1 -0
  42. package/dist/types/features/properties-panel/groups/ValidationGroup.d.ts +1 -0
  43. package/dist/types/features/properties-panel/groups/ValuesGroups.d.ts +1 -1
  44. package/dist/types/features/properties-panel/index.d.ts +2 -0
  45. package/dist/types/index.d.ts +2 -0
  46. package/dist/types/types.d.ts +28 -28
  47. package/package.json +4 -4
package/dist/index.es.js CHANGED
@@ -1,13 +1,13 @@
1
- import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Text as Text$1, FormFields, formFields, FormContext, FormRenderContext, FormComponent, Importer, PathRegistry, FormLayouter, FieldFactory, runRecursively, clone, getSchemaVariables, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_PATHS, VALUES_SOURCES_LABELS, FeelExpressionLanguage, createFormContainer, createInjector, MarkdownModule, schemaVersion } from '@bpmn-io/form-js-viewer';
1
+ import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Text as Text$1, FormFields, sanitizeImageSource, FormContext, FormRenderContext, FormComponent, Importer, PathRegistry, FormLayouter, FieldFactory, runRecursively, clone, getSchemaVariables, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_PATHS, VALUES_SOURCES_LABELS, FeelExpressionLanguage, createFormContainer, createInjector, MarkdownModule, schemaVersion } from '@bpmn-io/form-js-viewer';
2
2
  export { schemaVersion } from '@bpmn-io/form-js-viewer';
3
3
  import Ids from 'ids';
4
- import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, set as set$1, isString, isUndefined, without, has } from 'min-dash';
4
+ import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, isString, set as set$1, reduce, isUndefined, without, has } from 'min-dash';
5
5
  import classnames from 'classnames';
6
6
  import { jsx, jsxs, Fragment as Fragment$1 } from 'preact/jsx-runtime';
7
- import { useContext, useState, useMemo, useEffect, useCallback, useRef as useRef$1, useLayoutEffect } from 'preact/hooks';
7
+ import { useContext, useRef, useEffect, useMemo, useState, useCallback, useLayoutEffect } from 'preact/hooks';
8
8
  import { createContext, Fragment, render, createElement } from 'preact';
9
9
  import * as React from 'preact/compat';
10
- import { createPortal, useRef, useContext as useContext$1, useEffect as useEffect$1, forwardRef } from 'preact/compat';
10
+ import { createPortal, useRef as useRef$1, useContext as useContext$1, useEffect as useEffect$1, forwardRef } from 'preact/compat';
11
11
  import dragula from '@bpmn-io/draggle';
12
12
  import { classes, query, closest, event, matches, domify } from 'min-dom';
13
13
  import { mutate } from 'array-move';
@@ -18,7 +18,7 @@ import * as focusTrap from 'focus-trap';
18
18
  import Big from 'big.js';
19
19
 
20
20
  var FN_REF = '__fn';
21
- var DEFAULT_PRIORITY$2 = 1000;
21
+ var DEFAULT_PRIORITY$3 = 1000;
22
22
  var slice = Array.prototype.slice;
23
23
 
24
24
  /**
@@ -163,7 +163,7 @@ EventBus.prototype.on = function (events, priority, callback, that) {
163
163
  if (isFunction(priority)) {
164
164
  that = callback;
165
165
  callback = priority;
166
- priority = DEFAULT_PRIORITY$2;
166
+ priority = DEFAULT_PRIORITY$3;
167
167
  }
168
168
  if (!isNumber(priority)) {
169
169
  throw new Error('priority must be a number');
@@ -202,7 +202,7 @@ EventBus.prototype.once = function (events, priority, callback, that) {
202
202
  if (isFunction(priority)) {
203
203
  that = callback;
204
204
  callback = priority;
205
- priority = DEFAULT_PRIORITY$2;
205
+ priority = DEFAULT_PRIORITY$3;
206
206
  }
207
207
  if (!isNumber(priority)) {
208
208
  throw new Error('priority must be a number');
@@ -517,10 +517,10 @@ function invokeFunction(fn, args) {
517
517
  return fn.apply(null, args);
518
518
  }
519
519
 
520
- /**
521
- * A factory to create a configurable debouncer.
522
- *
523
- * @param {number|boolean} [config=true]
520
+ /**
521
+ * A factory to create a configurable debouncer.
522
+ *
523
+ * @param {number|boolean} [config=true]
524
524
  */
525
525
  function DebounceFactory(config = true) {
526
526
  const timeout = typeof config === 'number' ? config : config ? 300 : 0;
@@ -533,11 +533,11 @@ function DebounceFactory(config = true) {
533
533
  DebounceFactory.$inject = ['config.debounce'];
534
534
 
535
535
  class FormFieldRegistry extends FormFieldRegistry$1 {
536
- /**
537
- * Updates a form fields id.
538
- *
539
- * @param {Object} formField
540
- * @param {string} newId
536
+ /**
537
+ * Updates a form fields id.
538
+ *
539
+ * @param {Object} formField
540
+ * @param {string} newId
541
541
  */
542
542
  updateId(formField, newId) {
543
543
  this._validateId(newId);
@@ -558,13 +558,13 @@ class FormFieldRegistry extends FormFieldRegistry$1 {
558
558
  }
559
559
  }
560
560
 
561
- /**
562
- * Validate the suitability of the given id and signals a problem
563
- * with an exception.
564
- *
565
- * @param {string} id
566
- *
567
- * @throws {Error} if id is empty or already assigned
561
+ /**
562
+ * Validate the suitability of the given id and signals a problem
563
+ * with an exception.
564
+ *
565
+ * @param {string} id
566
+ *
567
+ * @throws {Error} if id is empty or already assigned
568
568
  */
569
569
  _validateId(id) {
570
570
  if (!id) {
@@ -581,11 +581,11 @@ const MAX_COLUMNS = 16;
581
581
  const MIN_COLUMNS = 2;
582
582
  const MAX_FIELDS_PER_ROW = 4;
583
583
  class FormLayoutValidator {
584
- /**
585
- * @constructor
586
- *
587
- * @param { import('./FormLayouter').default } formLayouter
588
- * @param { import('./FormFieldRegistry').default } formFieldRegistry
584
+ /**
585
+ * @constructor
586
+ *
587
+ * @param { import('./FormLayouter').default } formLayouter
588
+ * @param { import('./FormFieldRegistry').default } formFieldRegistry
589
589
  */
590
590
  constructor(formLayouter, formFieldRegistry) {
591
591
  this._formLayouter = formLayouter;
@@ -656,21 +656,21 @@ function editorFormFieldClasses(type, {
656
656
  });
657
657
  }
658
658
 
659
- /**
660
- * Add a dragger that calls back the passed function with
661
- * { event, delta } on drag.
662
- *
663
- * @example
664
- *
665
- * function dragMove(event, delta) {
666
- * // we are dragging (!!)
667
- * }
668
- *
669
- * domElement.addEventListener('dragstart', dragger(dragMove));
670
- *
671
- * @param {Function} fn
672
- *
673
- * @return {Function} drag start callback function
659
+ /**
660
+ * Add a dragger that calls back the passed function with
661
+ * { event, delta } on drag.
662
+ *
663
+ * @example
664
+ *
665
+ * function dragMove(event, delta) {
666
+ * // we are dragging (!!)
667
+ * }
668
+ *
669
+ * domElement.addEventListener('dragstart', dragger(dragMove));
670
+ *
671
+ * @param {Function} fn
672
+ *
673
+ * @return {Function} drag start callback function
674
674
  */
675
675
  function createDragger$1(fn) {
676
676
  let self;
@@ -711,12 +711,12 @@ function createDragger$1(fn) {
711
711
  return onDragStart;
712
712
  }
713
713
 
714
- /**
715
- * Throttle function call according UI update cycle.
716
- *
717
- * @param {Function} fn
718
- *
719
- * @return {Function} throttled fn
714
+ /**
715
+ * Throttle function call according UI update cycle.
716
+ *
717
+ * @param {Function} fn
718
+ *
719
+ * @return {Function} throttled fn
720
720
  */
721
721
  function throttle(fn) {
722
722
  let active = false;
@@ -750,11 +750,11 @@ const DragAndDropContext = createContext({
750
750
  });
751
751
  var DragAndDropContext$1 = DragAndDropContext;
752
752
 
753
- /**
754
- * @param {string} type
755
- * @param {boolean} [strict]
756
- *
757
- * @returns {any}
753
+ /**
754
+ * @param {string} type
755
+ * @param {boolean} [strict]
756
+ *
757
+ * @returns {any}
758
758
  */
759
759
  function getService$1(type, strict) {}
760
760
  const FormEditorContext = createContext({
@@ -769,6 +769,27 @@ function useService$1 (type, strict) {
769
769
  return getService(type, strict);
770
770
  }
771
771
 
772
+ function usePrevious$1(value) {
773
+ const ref = useRef();
774
+ useEffect(() => ref.current = value);
775
+ return ref.current;
776
+ }
777
+
778
+ function useDebounce(fn, dependencies = []) {
779
+ const debounce = useService$1('debounce');
780
+ const callback = useMemo(() => {
781
+ return debounce(fn);
782
+ }, dependencies);
783
+
784
+ // cleanup async side-effect if callback #flush is provided.
785
+ useEffect(() => {
786
+ return () => {
787
+ typeof callback.flush === 'function' && callback.flush();
788
+ };
789
+ }, [callback]);
790
+ return callback;
791
+ }
792
+
772
793
  var _path$4;
773
794
  function _extends$4() { _extends$4 = 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$4.apply(this, arguments); }
774
795
  var SvgClose = function SvgClose(props) {
@@ -1062,7 +1083,7 @@ const FillContext = createContext({
1062
1083
  var FillContext$1 = FillContext;
1063
1084
 
1064
1085
  var Fill = (props => {
1065
- const uid = useRef(Symbol('fill_uid'));
1086
+ const uid = useRef$1(Symbol('fill_uid'));
1066
1087
  const fillContext = useContext$1(FillContext$1);
1067
1088
  useEffect$1(() => {
1068
1089
  if (!fillContext) {
@@ -1104,23 +1125,23 @@ var Slot = (props => {
1104
1125
  return fillsAndSeparators;
1105
1126
  });
1106
1127
 
1107
- /**
1108
- * Creates a Fragment for a fill.
1109
- *
1110
- * @param {Object} fill Fill to be rendered
1111
- * @returns {Object} Preact Fragment containing fill's children
1128
+ /**
1129
+ * Creates a Fragment for a fill.
1130
+ *
1131
+ * @param {Object} fill Fill to be rendered
1132
+ * @returns {Object} Preact Fragment containing fill's children
1112
1133
  */
1113
1134
  const FillFragment = fill => jsx(Fragment, {
1114
1135
  children: fill.children
1115
1136
  }, fill.id);
1116
1137
 
1117
- /**
1118
- * Creates an array of fills, with separators inserted between groups.
1119
- *
1120
- * @param {Array} groups Groups of fills
1121
- * @param {Function} fillRenderer Function to create a fill
1122
- * @param {Function} separatorRenderer Function to create a separator
1123
- * @returns {Array} Array of fills and separators
1138
+ /**
1139
+ * Creates an array of fills, with separators inserted between groups.
1140
+ *
1141
+ * @param {Array} groups Groups of fills
1142
+ * @param {Function} fillRenderer Function to create a fill
1143
+ * @param {Function} separatorRenderer Function to create a separator
1144
+ * @returns {Array} Array of fills and separators
1124
1145
  */
1125
1146
  const buildFills = (groups, fillRenderer, separatorRenderer) => {
1126
1147
  const result = [];
@@ -1138,8 +1159,8 @@ const buildFills = (groups, fillRenderer, separatorRenderer) => {
1138
1159
  return result;
1139
1160
  };
1140
1161
 
1141
- /**
1142
- * Groups fills by group name property.
1162
+ /**
1163
+ * Groups fills by group name property.
1143
1164
  */
1144
1165
  const _groupByGroupName = fills => {
1145
1166
  const groups = [];
@@ -1159,8 +1180,8 @@ const _groupByGroupName = fills => {
1159
1180
  return Object.keys(groupsById).sort().map(id => groupsById[id]);
1160
1181
  };
1161
1182
 
1162
- /**
1163
- * Compares fills by priority.
1183
+ /**
1184
+ * Compares fills by priority.
1164
1185
  */
1165
1186
  const _comparePriority = (a, b) => {
1166
1187
  return (b.priority || 0) - (a.priority || 0);
@@ -1191,17 +1212,63 @@ var SlotFillRoot = (props => {
1191
1212
  });
1192
1213
  });
1193
1214
 
1194
- const PALETTE_ENTRIES = formFields.filter(({
1195
- config: fieldConfig
1196
- }) => fieldConfig.type !== 'default').map(({
1197
- config: fieldConfig
1198
- }) => {
1199
- return {
1200
- label: fieldConfig.label,
1201
- type: fieldConfig.type,
1202
- group: fieldConfig.group
1215
+ function PaletteEntry(props) {
1216
+ const {
1217
+ type,
1218
+ label,
1219
+ icon,
1220
+ iconUrl,
1221
+ getPaletteIcon
1222
+ } = props;
1223
+ const modeling = useService$1('modeling');
1224
+ const formEditor = useService$1('formEditor');
1225
+ const Icon = getPaletteIcon({
1226
+ icon,
1227
+ iconUrl,
1228
+ label,
1229
+ type
1230
+ });
1231
+ const onKeyDown = event => {
1232
+ if (event.code === 'Enter') {
1233
+ const {
1234
+ fieldType: type
1235
+ } = event.target.dataset;
1236
+ const {
1237
+ schema
1238
+ } = formEditor._getState();
1239
+
1240
+ // add new form field to last position
1241
+ modeling.addFormField({
1242
+ type
1243
+ }, schema, schema.components.length);
1244
+ }
1203
1245
  };
1204
- });
1246
+ return jsxs("button", {
1247
+ class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
1248
+ "data-field-type": type,
1249
+ title: `Create ${getIndefiniteArticle(type)} ${label} element`,
1250
+ onKeyDown: onKeyDown,
1251
+ children: [Icon ? jsx(Icon, {
1252
+ class: "fjs-palette-field-icon",
1253
+ width: "36",
1254
+ height: "36",
1255
+ viewBox: "0 0 54 54"
1256
+ }) : null, jsx("span", {
1257
+ class: "fjs-palette-field-text",
1258
+ children: label
1259
+ })]
1260
+ });
1261
+ }
1262
+
1263
+ // helpers ///////////
1264
+
1265
+ function getIndefiniteArticle(type) {
1266
+ if (['image'].includes(type)) {
1267
+ return 'an';
1268
+ }
1269
+ return 'a';
1270
+ }
1271
+
1205
1272
  const PALETTE_GROUPS = [{
1206
1273
  label: 'Basic input',
1207
1274
  id: 'basic-input'
@@ -1216,10 +1283,12 @@ const PALETTE_GROUPS = [{
1216
1283
  id: 'action'
1217
1284
  }];
1218
1285
  function Palette(props) {
1219
- const [entries, setEntries] = useState(PALETTE_ENTRIES);
1286
+ const formFields = useService$1('formFields');
1287
+ const initialPaletteEntries = useRef(collectPaletteEntries(formFields));
1288
+ const [paletteEntries, setPaletteEntries] = useState(initialPaletteEntries.current);
1220
1289
  const [searchTerm, setSearchTerm] = useState('');
1221
- const inputRef = useRef$1();
1222
- const groups = groupEntries(entries);
1290
+ const inputRef = useRef();
1291
+ const groups = groupEntries(paletteEntries);
1223
1292
  const simplifyString = useCallback(str => {
1224
1293
  return str.toLowerCase().replace(/\s+/g, '');
1225
1294
  }, []);
@@ -1235,8 +1304,8 @@ function Palette(props) {
1235
1304
 
1236
1305
  // filter entries on search change
1237
1306
  useEffect(() => {
1238
- const entries = PALETTE_ENTRIES.filter(filter);
1239
- setEntries(entries);
1307
+ const entries = initialPaletteEntries.current.filter(filter);
1308
+ setPaletteEntries(entries);
1240
1309
  }, [filter, searchTerm]);
1241
1310
  const handleInput = useCallback(event => {
1242
1311
  setSearchTerm(() => event.target.value);
@@ -1283,24 +1352,10 @@ function Palette(props) {
1283
1352
  children: label
1284
1353
  }), jsx("div", {
1285
1354
  class: "fjs-palette-fields fjs-drag-container fjs-no-drop",
1286
- children: entries.map(({
1287
- label,
1288
- type
1289
- }) => {
1290
- const Icon = iconsByType(type);
1291
- return jsxs("div", {
1292
- class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
1293
- "data-field-type": type,
1294
- title: `Create ${getIndefiniteArticle(type)} ${label} element`,
1295
- children: [Icon ? jsx(Icon, {
1296
- class: "fjs-palette-field-icon",
1297
- width: "36",
1298
- height: "36",
1299
- viewBox: "0 0 54 54"
1300
- }) : null, jsx("span", {
1301
- class: "fjs-palette-field-text",
1302
- children: label
1303
- })]
1355
+ children: entries.map(entry => {
1356
+ return jsx(PaletteEntry, {
1357
+ getPaletteIcon: getPaletteIcon,
1358
+ ...entry
1304
1359
  });
1305
1360
  })
1306
1361
  })]
@@ -1340,11 +1395,59 @@ function groupEntries(entries) {
1340
1395
  });
1341
1396
  return groups.filter(g => g.entries.length);
1342
1397
  }
1343
- function getIndefiniteArticle(type) {
1344
- if (['image'].includes(type)) {
1345
- return 'an';
1398
+
1399
+ /**
1400
+ * Returns a list of palette entries.
1401
+ *
1402
+ * @param {FormFields} formFields
1403
+ * @returns {Array<PaletteEntry>}
1404
+ */
1405
+ function collectPaletteEntries(formFields) {
1406
+ return Object.entries(formFields._formFields).map(([type, formField]) => {
1407
+ const {
1408
+ config: fieldConfig
1409
+ } = formField;
1410
+ return {
1411
+ label: fieldConfig.label,
1412
+ type: type,
1413
+ group: fieldConfig.group,
1414
+ icon: fieldConfig.icon,
1415
+ iconUrl: fieldConfig.iconUrl
1416
+ };
1417
+ }).filter(({
1418
+ type
1419
+ }) => type !== 'default');
1420
+ }
1421
+
1422
+ /**
1423
+ * There are various options to specify an icon for a palette entry.
1424
+ *
1425
+ * a) via `iconUrl` property in a form field config
1426
+ * b) via `icon` property in a form field config
1427
+ * c) via statically defined iconsByType (fallback)
1428
+ */
1429
+ function getPaletteIcon(entry) {
1430
+ const {
1431
+ icon,
1432
+ iconUrl,
1433
+ type,
1434
+ label
1435
+ } = entry;
1436
+ let Icon;
1437
+ if (iconUrl) {
1438
+ Icon = () => jsx("img", {
1439
+ class: "fjs-field-icon-image",
1440
+ width: 36,
1441
+ style: {
1442
+ margin: 'auto'
1443
+ },
1444
+ alt: label,
1445
+ src: sanitizeImageSource(iconUrl)
1446
+ });
1447
+ } else {
1448
+ Icon = icon || iconsByType(type);
1346
1449
  }
1347
- return 'a';
1450
+ return Icon;
1348
1451
  }
1349
1452
 
1350
1453
  var InjectedRendersRoot = (() => {
@@ -1388,20 +1491,20 @@ const DRAG_NO_DROP_CLS = 'fjs-no-drop';
1388
1491
  const DRAG_NO_MOVE_CLS = 'fjs-no-move';
1389
1492
  const ERROR_DROP_CLS = 'fjs-error-drop';
1390
1493
 
1391
- /**
1392
- * @typedef { { id: String, components: Array<any> } } FormRow
1494
+ /**
1495
+ * @typedef { { id: String, components: Array<any> } } FormRow
1393
1496
  */
1394
1497
 
1395
1498
  class Dragging {
1396
- /**
1397
- * @constructor
1398
- *
1399
- * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1400
- * @param { import('../../core/FormLayouter').default } formLayouter
1401
- * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1402
- * @param { import('../../core/EventBus').default } eventBus
1403
- * @param { import('../modeling/Modeling').default } modeling
1404
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
1499
+ /**
1500
+ * @constructor
1501
+ *
1502
+ * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1503
+ * @param { import('../../core/FormLayouter').default } formLayouter
1504
+ * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1505
+ * @param { import('../../core/EventBus').default } eventBus
1506
+ * @param { import('../modeling/Modeling').default } modeling
1507
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
1405
1508
  */
1406
1509
  constructor(formFieldRegistry, formLayouter, formLayoutValidator, eventBus, modeling, pathRegistry) {
1407
1510
  this._formFieldRegistry = formFieldRegistry;
@@ -1412,13 +1515,13 @@ class Dragging {
1412
1515
  this._pathRegistry = pathRegistry;
1413
1516
  }
1414
1517
 
1415
- /**
1416
- * Calculcates position in form schema given the dropped place.
1417
- *
1418
- * @param { FormRow } targetRow
1419
- * @param { any } targetFormField
1420
- * @param { HTMLElement } sibling
1421
- * @returns { number }
1518
+ /**
1519
+ * Calculcates position in form schema given the dropped place.
1520
+ *
1521
+ * @param { FormRow } targetRow
1522
+ * @param { any } targetFormField
1523
+ * @param { HTMLElement } sibling
1524
+ * @returns { number }
1422
1525
  */
1423
1526
  getTargetIndex(targetRow, targetFormField, sibling) {
1424
1527
  /** @type HTMLElement */
@@ -1559,8 +1662,8 @@ class Dragging {
1559
1662
  }
1560
1663
  }
1561
1664
 
1562
- /**
1563
- * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1665
+ /**
1666
+ * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1564
1667
  */
1565
1668
  createDragulaInstance(options) {
1566
1669
  const {
@@ -1731,13 +1834,13 @@ function FieldResizer(props) {
1731
1834
  field,
1732
1835
  position
1733
1836
  } = props;
1734
- const ref = useRef$1(null);
1837
+ const ref = useRef(null);
1735
1838
  const formLayoutValidator = useService$1('formLayoutValidator');
1736
1839
  const modeling = useService$1('modeling');
1737
1840
 
1738
1841
  // we can't use state as we need to
1739
1842
  // manipulate this inside dragging events
1740
- const context = useRef$1({
1843
+ const context = useRef({
1741
1844
  startColumns: 0,
1742
1845
  newColumns: 0
1743
1846
  });
@@ -1881,7 +1984,7 @@ function Element$1(props) {
1881
1984
  type,
1882
1985
  showOutline
1883
1986
  } = field;
1884
- const ref = useRef$1();
1987
+ const ref = useRef();
1885
1988
  function scrollIntoView({
1886
1989
  selection
1887
1990
  }) {
@@ -1974,7 +2077,7 @@ function DebugColumns(props) {
1974
2077
  return null;
1975
2078
  }
1976
2079
  return jsx("div", {
1977
- style: "width: fit-content;\r padding: 2px 6px;\r height: 16px;\r background: var(--color-blue-205-100-95);\r display: flex;\r justify-content: center;\r align-items: center;\r position: absolute;\r bottom: -2px;\r z-index: 2;\r font-size: 10px;\r right: 3px;",
2080
+ 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;",
1978
2081
  class: "fjs-debug-columns",
1979
2082
  children: (field.layout || {}).columns || 'auto'
1980
2083
  });
@@ -2051,8 +2154,8 @@ function FormEditor$1(props) {
2051
2154
  const {
2052
2155
  ariaLabel
2053
2156
  } = properties;
2054
- const formContainerRef = useRef$1(null);
2055
- const propertiesPanelRef = useRef$1(null);
2157
+ const formContainerRef = useRef(null);
2158
+ const propertiesPanelRef = useRef(null);
2056
2159
  const [, setSelection] = useState(schema);
2057
2160
  useEffect(() => {
2058
2161
  function handleSelectionChanged(event) {
@@ -2114,6 +2217,9 @@ function FormEditor$1(props) {
2114
2217
 
2115
2218
  // fire event after render to notify interested parties
2116
2219
  useEffect(() => {
2220
+ eventBus.fire('rendered');
2221
+
2222
+ // keep deprecated event to ensure backward compatibility
2117
2223
  eventBus.fire('formEditor.rendered');
2118
2224
  }, []);
2119
2225
  const [hoveredId, setHoveredId] = useState(null);
@@ -2209,15 +2315,20 @@ function CreatePreview(props) {
2209
2315
  const {
2210
2316
  drake
2211
2317
  } = useContext(DragAndDropContext$1);
2318
+ const formFields = useService$1('formFields');
2212
2319
  function handleCloned(clone, original, type) {
2213
2320
  const fieldType = clone.dataset.fieldType;
2214
2321
 
2215
2322
  // (1) field preview
2216
2323
  if (fieldType) {
2324
+ const paletteEntry = findPaletteEntry(fieldType, formFields);
2325
+ if (!paletteEntry) {
2326
+ return;
2327
+ }
2217
2328
  const {
2218
2329
  label
2219
- } = findPaletteEntry(fieldType);
2220
- const Icon = iconsByType(fieldType);
2330
+ } = paletteEntry;
2331
+ const Icon = getPaletteIcon(paletteEntry);
2221
2332
  clone.innerHTML = '';
2222
2333
  clone.class = 'gu-mirror';
2223
2334
  clone.classList.add('fjs-field-preview-container');
@@ -2258,8 +2369,8 @@ function CreatePreview(props) {
2258
2369
 
2259
2370
  // helper //////
2260
2371
 
2261
- function findPaletteEntry(type) {
2262
- return PALETTE_ENTRIES.find(entry => entry.type === type);
2372
+ function findPaletteEntry(type, formFields) {
2373
+ return collectPaletteEntries(formFields).find(entry => entry.type === type);
2263
2374
  }
2264
2375
  function defaultPropertiesPanel(propertiesPanelConfig) {
2265
2376
  return !(propertiesPanelConfig && propertiesPanelConfig.parent);
@@ -2674,7 +2785,7 @@ function isRedo(event) {
2674
2785
  var KEYDOWN_EVENT = 'keyboard.keydown',
2675
2786
  KEYUP_EVENT = 'keyboard.keyup';
2676
2787
  var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
2677
- var DEFAULT_PRIORITY$1 = 1000;
2788
+ var DEFAULT_PRIORITY$2 = 1000;
2678
2789
 
2679
2790
  /**
2680
2791
  * A keyboard abstraction that may be activated and
@@ -2807,7 +2918,7 @@ Keyboard.prototype.addListener = function (priority, listener, type) {
2807
2918
  if (isFunction(priority)) {
2808
2919
  type = listener;
2809
2920
  listener = priority;
2810
- priority = DEFAULT_PRIORITY$1;
2921
+ priority = DEFAULT_PRIORITY$2;
2811
2922
  }
2812
2923
  this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
2813
2924
  };
@@ -3045,10 +3156,10 @@ function updateRow(formField, rowId) {
3045
3156
  }
3046
3157
 
3047
3158
  class AddFormFieldHandler {
3048
- /**
3049
- * @constructor
3050
- * @param { import('../../../FormEditor').default } formEditor
3051
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3159
+ /**
3160
+ * @constructor
3161
+ * @param { import('../../../FormEditor').default } formEditor
3162
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3052
3163
  */
3053
3164
  constructor(formEditor, formFieldRegistry) {
3054
3165
  this._formEditor = formEditor;
@@ -3109,10 +3220,10 @@ class AddFormFieldHandler {
3109
3220
  AddFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3110
3221
 
3111
3222
  class EditFormFieldHandler {
3112
- /**
3113
- * @constructor
3114
- * @param { import('../../../FormEditor').default } formEditor
3115
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3223
+ /**
3224
+ * @constructor
3225
+ * @param { import('../../../FormEditor').default } formEditor
3226
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3116
3227
  */
3117
3228
  constructor(formEditor, formFieldRegistry) {
3118
3229
  this._formEditor = formEditor;
@@ -3175,11 +3286,11 @@ class EditFormFieldHandler {
3175
3286
  EditFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3176
3287
 
3177
3288
  class MoveFormFieldHandler {
3178
- /**
3179
- * @constructor
3180
- * @param { import('../../../FormEditor').default } formEditor
3181
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3182
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3289
+ /**
3290
+ * @constructor
3291
+ * @param { import('../../../FormEditor').default } formEditor
3292
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3293
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3183
3294
  */
3184
3295
  constructor(formEditor, formFieldRegistry, pathRegistry) {
3185
3296
  this._formEditor = formEditor;
@@ -3284,10 +3395,10 @@ class MoveFormFieldHandler {
3284
3395
  MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry', 'pathRegistry'];
3285
3396
 
3286
3397
  class RemoveFormFieldHandler {
3287
- /**
3288
- * @constructor
3289
- * @param { import('../../../FormEditor').default } formEditor
3290
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3398
+ /**
3399
+ * @constructor
3400
+ * @param { import('../../../FormEditor').default } formEditor
3401
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3291
3402
  */
3292
3403
  constructor(formEditor, formFieldRegistry) {
3293
3404
  this._formEditor = formEditor;
@@ -3347,9 +3458,9 @@ class RemoveFormFieldHandler {
3347
3458
  RemoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3348
3459
 
3349
3460
  class UpdateIdClaimHandler {
3350
- /**
3351
- * @constructor
3352
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3461
+ /**
3462
+ * @constructor
3463
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3353
3464
  */
3354
3465
  constructor(formFieldRegistry) {
3355
3466
  this._formFieldRegistry = formFieldRegistry;
@@ -3382,9 +3493,9 @@ class UpdateIdClaimHandler {
3382
3493
  UpdateIdClaimHandler.$inject = ['formFieldRegistry'];
3383
3494
 
3384
3495
  class UpdateKeyClaimHandler {
3385
- /**
3386
- * @constructor
3387
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3496
+ /**
3497
+ * @constructor
3498
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3388
3499
  */
3389
3500
  constructor(pathRegistry) {
3390
3501
  this._pathRegistry = pathRegistry;
@@ -3425,9 +3536,9 @@ class UpdateKeyClaimHandler {
3425
3536
  UpdateKeyClaimHandler.$inject = ['pathRegistry'];
3426
3537
 
3427
3538
  class UpdatePathClaimHandler {
3428
- /**
3429
- * @constructor
3430
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3539
+ /**
3540
+ * @constructor
3541
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3431
3542
  */
3432
3543
  constructor(pathRegistry) {
3433
3544
  this._pathRegistry = pathRegistry;
@@ -3625,7 +3736,7 @@ Modeling.$inject = ['commandStack', 'eventBus', 'formEditor', 'formFieldRegistry
3625
3736
  * @typedef { (context: CommandContext) => void } ComposeHandlerFunction
3626
3737
  */
3627
3738
 
3628
- var DEFAULT_PRIORITY = 1000;
3739
+ var DEFAULT_PRIORITY$1 = 1000;
3629
3740
 
3630
3741
  /**
3631
3742
  * A utility that can be used to plug into the command execution for
@@ -3686,7 +3797,7 @@ CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, u
3686
3797
  that = unwrap;
3687
3798
  unwrap = handlerFn;
3688
3799
  handlerFn = priority;
3689
- priority = DEFAULT_PRIORITY;
3800
+ priority = DEFAULT_PRIORITY$1;
3690
3801
  }
3691
3802
  if (isObject(unwrap)) {
3692
3803
  that = unwrap;
@@ -3989,8 +4100,8 @@ class ValidateBehavior extends CommandInterceptor {
3989
4100
  constructor(eventBus) {
3990
4101
  super(eventBus);
3991
4102
 
3992
- /**
3993
- * Remove custom validation if <validationType> is about to be added.
4103
+ /**
4104
+ * Remove custom validation if <validationType> is about to be added.
3994
4105
  */
3995
4106
  this.preExecute('formField.edit', function (context) {
3996
4107
  const {
@@ -4570,22 +4681,22 @@ var SelectionModule = {
4570
4681
  selectionBehavior: ['type', SelectionBehavior]
4571
4682
  };
4572
4683
 
4573
- /**
4574
- * Base class for sectionable UI modules.
4575
- *
4576
- * @property {EventBus} _eventBus - EventBus instance used for event handling.
4577
- * @property {string} managerType - Type of the render manager. Used to form event names.
4578
- *
4579
- * @class SectionModuleBase
4684
+ /**
4685
+ * Base class for sectionable UI modules.
4686
+ *
4687
+ * @property {EventBus} _eventBus - EventBus instance used for event handling.
4688
+ * @property {string} managerType - Type of the render manager. Used to form event names.
4689
+ *
4690
+ * @class SectionModuleBase
4580
4691
  */
4581
4692
  class SectionModuleBase {
4582
- /**
4583
- * Create a SectionModuleBase instance.
4584
- *
4585
- * @param {any} eventBus - The EventBus instance used for event handling.
4586
- * @param {string} sectionKey - The type of render manager. Used to form event names.
4587
- *
4588
- * @constructor
4693
+ /**
4694
+ * Create a SectionModuleBase instance.
4695
+ *
4696
+ * @param {any} eventBus - The EventBus instance used for event handling.
4697
+ * @param {string} sectionKey - The type of render manager. Used to form event names.
4698
+ *
4699
+ * @constructor
4589
4700
  */
4590
4701
  constructor(eventBus, sectionKey) {
4591
4702
  this._eventBus = eventBus;
@@ -4598,10 +4709,10 @@ class SectionModuleBase {
4598
4709
  });
4599
4710
  }
4600
4711
 
4601
- /**
4602
- * Attach the managed section to a parent node.
4603
- *
4604
- * @param {HTMLElement} container - The parent node to attach to.
4712
+ /**
4713
+ * Attach the managed section to a parent node.
4714
+ *
4715
+ * @param {HTMLElement} container - The parent node to attach to.
4605
4716
  */
4606
4717
  attachTo(container) {
4607
4718
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.attach`, {
@@ -4609,22 +4720,22 @@ class SectionModuleBase {
4609
4720
  }));
4610
4721
  }
4611
4722
 
4612
- /**
4613
- * Detach the managed section from its parent node.
4723
+ /**
4724
+ * Detach the managed section from its parent node.
4614
4725
  */
4615
4726
  detach() {
4616
4727
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.detach`));
4617
4728
  }
4618
4729
 
4619
- /**
4620
- * Reset the managed section to its initial state.
4730
+ /**
4731
+ * Reset the managed section to its initial state.
4621
4732
  */
4622
4733
  reset() {
4623
4734
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.reset`));
4624
4735
  }
4625
4736
 
4626
- /**
4627
- * Circumvents timing issues.
4737
+ /**
4738
+ * Circumvents timing issues.
4628
4739
  */
4629
4740
  _onceSectionRendered(callback) {
4630
4741
  if (this.isSectionRendered) {
@@ -4877,8 +4988,8 @@ function Tooltip(props) {
4877
4988
  const [visible, setShow] = useState(false);
4878
4989
  const [focusedViaKeyboard, setFocusedViaKeyboard] = useState(false);
4879
4990
  let timeout = null;
4880
- const wrapperRef = useRef$1(null);
4881
- const tooltipRef = useRef$1(null);
4991
+ const wrapperRef = useRef(null);
4992
+ const tooltipRef = useRef(null);
4882
4993
  const showTooltip = async event => {
4883
4994
  const show = () => setShow(true);
4884
4995
  if (!visible && !timeout) {
@@ -5041,7 +5152,7 @@ function useEvent(event, callback, eventBus) {
5041
5152
  eventBus
5042
5153
  } = eventContext);
5043
5154
  }
5044
- const didMount = useRef$1(false);
5155
+ const didMount = useRef(false);
5045
5156
 
5046
5157
  // (1) subscribe immediately
5047
5158
  if (eventBus && !didMount.current) {
@@ -5097,7 +5208,7 @@ function useLayoutState(path, defaultValue) {
5097
5208
  */
5098
5209
 
5099
5210
  function usePrevious(value) {
5100
- const ref = useRef$1();
5211
+ const ref = useRef();
5101
5212
  useEffect(() => {
5102
5213
  ref.current = value;
5103
5214
  });
@@ -5115,8 +5226,8 @@ function useShowEntryEvent(id) {
5115
5226
  const {
5116
5227
  onShow
5117
5228
  } = useContext(LayoutContext);
5118
- const ref = useRef$1();
5119
- const focus = useRef$1(false);
5229
+ const ref = useRef();
5230
+ const focus = useRef(false);
5120
5231
  const onShowEntry = useCallback(event => {
5121
5232
  if (event.id === id) {
5122
5233
  onShow();
@@ -5222,7 +5333,7 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
5222
5333
  * @returns {Function} static function reference
5223
5334
  */
5224
5335
  function useStaticCallback(callback) {
5225
- const callbackRef = useRef$1(callback);
5336
+ const callbackRef = useRef(callback);
5226
5337
  callbackRef.current = callback;
5227
5338
  return useCallback((...args) => callbackRef.current(...args), []);
5228
5339
  }
@@ -5234,7 +5345,7 @@ function Group(props) {
5234
5345
  label,
5235
5346
  shouldOpen = false
5236
5347
  } = props;
5237
- const groupRef = useRef$1(null);
5348
+ const groupRef = useRef(null);
5238
5349
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
5239
5350
  const onShow = useCallback(() => setOpen(true), [setOpen]);
5240
5351
  const toggleOpen = () => setOpen(!open);
@@ -5424,7 +5535,7 @@ const CodeEditor$1 = forwardRef((props, ref) => {
5424
5535
  hostLanguage = null,
5425
5536
  singleLine = false
5426
5537
  } = props;
5427
- const inputRef = useRef$1();
5538
+ const inputRef = useRef();
5428
5539
  const [editor, setEditor] = useState();
5429
5540
  const [localValue, setLocalValue] = useState(value || '');
5430
5541
  useBufferedFocus$1(editor, ref);
@@ -5523,7 +5634,7 @@ const CodeEditor = forwardRef((props, ref) => {
5523
5634
  tooltipContainer,
5524
5635
  variables
5525
5636
  } = props;
5526
- const inputRef = useRef$1();
5637
+ const inputRef = useRef();
5527
5638
  const [editor, setEditor] = useState();
5528
5639
  const [localValue, setLocalValue] = useState(value || '');
5529
5640
  useBufferedFocus(editor, ref);
@@ -5755,9 +5866,10 @@ function PopupComponent(props, globalRef) {
5755
5866
  closeOnEscape = true,
5756
5867
  title
5757
5868
  } = props;
5758
- const focusTrapRef = useRef$1(null);
5759
- const localRef = useRef$1(null);
5869
+ const focusTrapRef = useRef(null);
5870
+ const localRef = useRef(null);
5760
5871
  const popupRef = globalRef || localRef;
5872
+ const containerNode = useMemo(() => getContainerNode(container), [container]);
5761
5873
  const handleKeydown = event => {
5762
5874
  // do not allow keyboard events to bubble
5763
5875
  event.stopPropagation();
@@ -5817,7 +5929,7 @@ function PopupComponent(props, globalRef) {
5817
5929
  class: classnames('bio-properties-panel-popup', className),
5818
5930
  style: style,
5819
5931
  children: props.children
5820
- }), container || document.body);
5932
+ }), containerNode || document.body);
5821
5933
  }
5822
5934
  const Popup = forwardRef(PopupComponent);
5823
5935
  Popup.Title = Title;
@@ -5835,12 +5947,12 @@ function Title(props) {
5835
5947
 
5836
5948
  // we can't use state as we need to
5837
5949
  // manipulate this inside dragging events
5838
- const context = useRef$1({
5950
+ const context = useRef({
5839
5951
  startPosition: null,
5840
5952
  newPosition: null
5841
5953
  });
5842
- const dragPreviewRef = useRef$1();
5843
- const titleRef = useRef$1();
5954
+ const dragPreviewRef = useRef();
5955
+ const titleRef = useRef();
5844
5956
  const onMove = (event, delta) => {
5845
5957
  cancel(event);
5846
5958
  const {
@@ -5937,6 +6049,12 @@ function cancel(event) {
5937
6049
  event.preventDefault();
5938
6050
  event.stopPropagation();
5939
6051
  }
6052
+ function getContainerNode(node) {
6053
+ if (typeof node === 'string') {
6054
+ return query(node);
6055
+ }
6056
+ return node;
6057
+ }
5940
6058
  const FEEL_POPUP_WIDTH = 700;
5941
6059
  const FEEL_POPUP_HEIGHT = 250;
5942
6060
 
@@ -6047,9 +6165,9 @@ function FeelPopupComponent(props) {
6047
6165
  variables,
6048
6166
  emit
6049
6167
  } = props;
6050
- const editorRef = useRef$1();
6051
- const popupRef = useRef$1();
6052
- const isAutoCompletionOpen = useRef$1(false);
6168
+ const editorRef = useRef();
6169
+ const popupRef = useRef();
6170
+ const isAutoCompletionOpen = useRef(false);
6053
6171
  const handleSetReturnFocus = () => {
6054
6172
  sourceElement && sourceElement.focus();
6055
6173
  };
@@ -6157,7 +6275,7 @@ function autoCompletionOpen(element) {
6157
6275
  * @param {Array} deps
6158
6276
  */
6159
6277
  function useUpdateEffect(effect, deps) {
6160
- const isMounted = useRef$1(false);
6278
+ const isMounted = useRef(false);
6161
6279
  useEffect(() => {
6162
6280
  if (isMounted.current) {
6163
6281
  return effect();
@@ -6461,7 +6579,7 @@ function FeelTextfield(props) {
6461
6579
  } = props;
6462
6580
  const [localValue, _setLocalValue] = useState(value);
6463
6581
  const editorRef = useShowEntryEvent(id);
6464
- const containerRef = useRef$1();
6582
+ const containerRef = useRef();
6465
6583
  const feelActive = isString(localValue) && localValue.startsWith('=') || feel === 'required';
6466
6584
  const feelOnlyValue = isString(localValue) && localValue.startsWith('=') ? localValue.substring(1) : localValue;
6467
6585
  const [focus, _setFocus] = useState(undefined);
@@ -6484,7 +6602,7 @@ function FeelTextfield(props) {
6484
6602
  }, [onInput, debounce]);
6485
6603
  const setLocalValue = newValue => {
6486
6604
  _setLocalValue(newValue);
6487
- if (!newValue || newValue === '=') {
6605
+ if (typeof newValue === 'undefined' || newValue === '' || newValue === '=') {
6488
6606
  handleInputCallback(undefined);
6489
6607
  } else {
6490
6608
  handleInputCallback(newValue);
@@ -6652,7 +6770,7 @@ const OptionalFeelInput = forwardRef((props, ref) => {
6652
6770
  onFocus,
6653
6771
  onBlur
6654
6772
  } = props;
6655
- const inputRef = useRef$1();
6773
+ const inputRef = useRef();
6656
6774
 
6657
6775
  // To be consistent with the FEEL editor, set focus at start of input
6658
6776
  // this ensures clean editing experience when switching with the keyboard
@@ -6699,7 +6817,7 @@ const OptionalFeelNumberField = forwardRef((props, ref) => {
6699
6817
  onFocus,
6700
6818
  onBlur
6701
6819
  } = props;
6702
- const inputRef = useRef$1();
6820
+ const inputRef = useRef();
6703
6821
 
6704
6822
  // To be consistent with the FEEL editor, set focus at start of input
6705
6823
  // this ensures clean editing experience when switching with the keyboard
@@ -6742,7 +6860,7 @@ forwardRef((props, ref) => {
6742
6860
  onFocus,
6743
6861
  onBlur
6744
6862
  } = props;
6745
- const inputRef = useRef$1();
6863
+ const inputRef = useRef();
6746
6864
 
6747
6865
  // To be consistent with the FEEL editor, set focus at start of input
6748
6866
  // this ensures clean editing experience when switching with the keyboard
@@ -6781,7 +6899,7 @@ const OptionalFeelToggleSwitch = forwardRef((props, ref) => {
6781
6899
  onBlur,
6782
6900
  switcherLabel
6783
6901
  } = props;
6784
- const inputRef = useRef$1();
6902
+ const inputRef = useRef();
6785
6903
 
6786
6904
  // To be consistent with the FEEL editor, set focus at start of input
6787
6905
  // this ensures clean editing experience when switching with the keyboard
@@ -6813,7 +6931,7 @@ forwardRef((props, ref) => {
6813
6931
  onFocus,
6814
6932
  onBlur
6815
6933
  } = props;
6816
- const inputRef = useRef$1();
6934
+ const inputRef = useRef();
6817
6935
  const handleChange = ({
6818
6936
  target
6819
6937
  }) => {
@@ -7327,7 +7445,7 @@ function createTooltipContext(overrides = {}) {
7327
7445
  * @param {Array} deps
7328
7446
  */
7329
7447
  function useUpdateLayoutEffect(effect, deps) {
7330
- const isMounted = useRef$1(false);
7448
+ const isMounted = useRef(false);
7331
7449
  useLayoutEffect(() => {
7332
7450
  if (isMounted.current) {
7333
7451
  return effect();
@@ -7446,7 +7564,7 @@ function ListGroup(props) {
7446
7564
  shouldOpen = true,
7447
7565
  shouldSort = true
7448
7566
  } = props;
7449
- const groupRef = useRef$1(null);
7567
+ const groupRef = useRef(null);
7450
7568
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
7451
7569
  const [sticky, setSticky] = useState(false);
7452
7570
  const onShow = useCallback(() => setOpen(true), [setOpen]);
@@ -8246,11 +8364,11 @@ var index = {
8246
8364
  feelPopup: ['type', FeelPopupModule]
8247
8365
  };
8248
8366
 
8249
- /**
8250
- * @param {string} type
8251
- * @param {boolean} [strict]
8252
- *
8253
- * @returns {any}
8367
+ /**
8368
+ * @param {string} type
8369
+ * @param {boolean} [strict]
8370
+ *
8371
+ * @returns {any}
8254
8372
  */
8255
8373
  function getService(type, strict) {}
8256
8374
  const PropertiesPanelContext = createContext({
@@ -8288,25 +8406,43 @@ function isValidDotPath(path) {
8288
8406
  }
8289
8407
  const INPUTS = ['checkbox', 'checklist', 'datetime', 'number', 'radio', 'select', 'taglist', 'textfield', 'textarea'];
8290
8408
  const VALUES_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
8409
+ function hasEntryConfigured(formFieldDefinition, entryId) {
8410
+ const {
8411
+ propertiesPanelEntries = []
8412
+ } = formFieldDefinition;
8413
+ if (!propertiesPanelEntries.length) {
8414
+ return false;
8415
+ }
8416
+ return propertiesPanelEntries.some(id => id === entryId);
8417
+ }
8418
+ function hasValuesGroupsConfigured(formFieldDefinition) {
8419
+ const {
8420
+ propertiesPanelEntries = []
8421
+ } = formFieldDefinition;
8422
+ if (!propertiesPanelEntries.length) {
8423
+ return false;
8424
+ }
8425
+ return propertiesPanelEntries.some(id => id === 'values');
8426
+ }
8427
+
8428
+ function useService (type, strict) {
8429
+ const {
8430
+ getService
8431
+ } = useContext(FormPropertiesPanelContext);
8432
+ return getService(type, strict);
8433
+ }
8434
+
8435
+ /**
8436
+ * Retrieve list of variables from the form schema.
8437
+ *
8438
+ * @returns { string[] } list of variables used in form schema
8439
+ */
8440
+ function useVariables() {
8441
+ const form = useService('formEditor');
8442
+ const schema = form.getSchema();
8443
+ return getSchemaVariables(schema);
8444
+ }
8291
8445
 
8292
- const labelsByType = {
8293
- button: 'BUTTON',
8294
- checkbox: 'CHECKBOX',
8295
- checklist: 'CHECKLIST',
8296
- columns: 'COLUMNS',
8297
- default: 'FORM',
8298
- datetime: 'DATETIME',
8299
- group: 'GROUP',
8300
- image: 'IMAGE VIEW',
8301
- number: 'NUMBER',
8302
- radio: 'RADIO',
8303
- select: 'SELECT',
8304
- spacer: 'SPACER',
8305
- taglist: 'TAGLIST',
8306
- text: 'TEXT VIEW',
8307
- textfield: 'TEXT FIELD',
8308
- textarea: 'TEXT AREA'
8309
- };
8310
8446
  const PropertiesPanelHeaderProvider = {
8311
8447
  getElementLabel: field => {
8312
8448
  const {
@@ -8330,25 +8466,43 @@ const PropertiesPanelHeaderProvider = {
8330
8466
  const {
8331
8467
  type
8332
8468
  } = field;
8333
- const Icon = iconsByType(type);
8469
+
8470
+ // @Note: We know that we are inside the properties panel context,
8471
+ // so we can savely use the hook here.
8472
+ // eslint-disable-next-line react-hooks/rules-of-hooks
8473
+ const fieldDefinition = useService('formFields').get(type).config;
8474
+ const Icon = fieldDefinition.icon || iconsByType(type);
8334
8475
  if (Icon) {
8335
8476
  return () => jsx(Icon, {
8336
8477
  width: "36",
8337
8478
  height: "36",
8338
8479
  viewBox: "0 0 54 54"
8339
8480
  });
8481
+ } else if (fieldDefinition.iconUrl) {
8482
+ return getPaletteIcon({
8483
+ iconUrl: fieldDefinition.iconUrl,
8484
+ label: fieldDefinition.label
8485
+ });
8340
8486
  }
8341
8487
  },
8342
8488
  getTypeLabel: field => {
8343
8489
  const {
8344
8490
  type
8345
8491
  } = field;
8346
- return labelsByType[type];
8492
+ if (type === 'default') {
8493
+ return 'Form';
8494
+ }
8495
+
8496
+ // @Note: We know that we are inside the properties panel context,
8497
+ // so we can savely use the hook here.
8498
+ // eslint-disable-next-line react-hooks/rules-of-hooks
8499
+ const fieldDefinition = useService('formFields').get(type).config;
8500
+ return fieldDefinition.label || type;
8347
8501
  }
8348
8502
  };
8349
8503
 
8350
- /**
8351
- * Provide placeholders for empty and multiple state.
8504
+ /**
8505
+ * Provide placeholders for empty and multiple state.
8352
8506
  */
8353
8507
  const PropertiesPanelPlaceholderProvider = {
8354
8508
  getEmpty: () => {
@@ -8363,92 +8517,256 @@ const PropertiesPanelPlaceholderProvider = {
8363
8517
  }
8364
8518
  };
8365
8519
 
8366
- function ActionEntry(props) {
8520
+ function FormPropertiesPanel(props) {
8367
8521
  const {
8368
- editField,
8369
- field
8522
+ eventBus,
8523
+ getProviders,
8524
+ injector
8370
8525
  } = props;
8526
+ const formEditor = injector.get('formEditor');
8527
+ const modeling = injector.get('modeling');
8528
+ const selectionModule = injector.get('selection');
8529
+ const propertiesPanelConfig = injector.get('config.propertiesPanel') || {};
8371
8530
  const {
8372
- type
8373
- } = field;
8374
- const entries = [];
8375
- if (type === 'button') {
8376
- entries.push({
8377
- id: 'action',
8378
- component: Action,
8379
- editField: editField,
8380
- field: field,
8381
- isEdited: isEdited$3
8382
- });
8383
- }
8384
- return entries;
8385
- }
8386
- function Action(props) {
8387
- const {
8388
- editField,
8389
- field,
8390
- id
8391
- } = props;
8392
- const path = ['action'];
8393
- const getValue = () => {
8394
- return get(field, path, '');
8395
- };
8396
- const setValue = value => {
8397
- return editField(field, path, value);
8398
- };
8399
- const getOptions = () => [{
8400
- label: 'Submit',
8401
- value: 'submit'
8402
- }, {
8403
- label: 'Reset',
8404
- value: 'reset'
8405
- }];
8406
- return SelectEntry({
8407
- element: field,
8408
- getOptions,
8409
- getValue,
8410
- id,
8411
- label: 'Action',
8412
- setValue
8531
+ feelPopupContainer
8532
+ } = propertiesPanelConfig;
8533
+ const [state, setState] = useState({
8534
+ selectedFormField: selectionModule.get() || formEditor._getState().schema
8413
8535
  });
8414
- }
8415
-
8416
- function useService (type, strict) {
8417
- const {
8536
+ const selectedFormField = state.selectedFormField;
8537
+ const refresh = useCallback(field => {
8538
+ // TODO(skaiir): rework state management, re-rendering the whole properties panel is not the way to go
8539
+ // https://github.com/bpmn-io/form-js/issues/686
8540
+ setState({
8541
+ selectedFormField: selectionModule.get() || formEditor._getState().schema
8542
+ });
8543
+
8544
+ // notify interested parties on property panel updates
8545
+ eventBus.fire('propertiesPanel.updated', {
8546
+ formField: field
8547
+ });
8548
+ }, [eventBus, formEditor, selectionModule]);
8549
+ useLayoutEffect(() => {
8550
+ /**
8551
+ * TODO(pinussilvestrus): update with actual updated element,
8552
+ * once we have a proper updater/change support
8553
+ */
8554
+ eventBus.on('changed', refresh);
8555
+ eventBus.on('import.done', refresh);
8556
+ eventBus.on('selection.changed', refresh);
8557
+ return () => {
8558
+ eventBus.off('changed', refresh);
8559
+ eventBus.off('import.done', refresh);
8560
+ eventBus.off('selection.changed', refresh);
8561
+ };
8562
+ }, [eventBus, refresh]);
8563
+ const getService = (type, strict = true) => injector.get(type, strict);
8564
+ const propertiesPanelContext = {
8418
8565
  getService
8419
- } = useContext(FormPropertiesPanelContext);
8420
- return getService(type, strict);
8566
+ };
8567
+ const onFocus = () => eventBus.fire('propertiesPanel.focusin');
8568
+ const onBlur = () => eventBus.fire('propertiesPanel.focusout');
8569
+ const editField = useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]);
8570
+
8571
+ // retrieve groups for selected form field
8572
+ const providers = getProviders(selectedFormField);
8573
+ const groups = useMemo(() => {
8574
+ return reduce(providers, function (groups, provider) {
8575
+ // do not collect groups for multi element state
8576
+ if (isArray(selectedFormField)) {
8577
+ return [];
8578
+ }
8579
+ const updater = provider.getGroups(selectedFormField, editField);
8580
+ return updater(groups);
8581
+ }, []);
8582
+ }, [providers, selectedFormField, editField]);
8583
+ return jsx("div", {
8584
+ class: "fjs-properties-panel",
8585
+ "data-field": selectedFormField && selectedFormField.id,
8586
+ onFocusCapture: onFocus,
8587
+ onBlurCapture: onBlur,
8588
+ children: jsx(FormPropertiesPanelContext.Provider, {
8589
+ value: propertiesPanelContext,
8590
+ children: jsx(PropertiesPanel, {
8591
+ element: selectedFormField,
8592
+ eventBus: eventBus,
8593
+ groups: groups,
8594
+ headerProvider: PropertiesPanelHeaderProvider,
8595
+ placeholderProvider: PropertiesPanelPlaceholderProvider,
8596
+ feelPopupContainer: feelPopupContainer
8597
+ })
8598
+ })
8599
+ });
8421
8600
  }
8422
8601
 
8423
- /**
8424
- * Retrieve list of variables from the form schema.
8425
- *
8426
- * @returns { string[] } list of variables used in form schema
8602
+ const DEFAULT_PRIORITY = 1000;
8603
+
8604
+ /**
8605
+ * @typedef { { parent: Element } } PropertiesPanelConfig
8606
+ * @typedef { import('../../core/EventBus').default } EventBus
8607
+ * @typedef { import('../../types').Injector } Injector
8608
+ * @typedef { { getGroups: ({ formField, editFormField }) => ({ groups}) => Array } } PropertiesProvider
8427
8609
  */
8428
- function useVariables() {
8429
- const form = useService('formEditor');
8430
- const schema = form.getSchema();
8431
- return getSchemaVariables(schema);
8610
+
8611
+ /**
8612
+ * @param {PropertiesPanelConfig} propertiesPanelConfig
8613
+ * @param {Injector} injector
8614
+ * @param {EventBus} eventBus
8615
+ */
8616
+ class PropertiesPanelRenderer {
8617
+ constructor(propertiesPanelConfig, injector, eventBus) {
8618
+ const {
8619
+ parent
8620
+ } = propertiesPanelConfig || {};
8621
+ this._eventBus = eventBus;
8622
+ this._injector = injector;
8623
+ this._container = domify('<div class="fjs-properties-container" input-handle-modified-keys="y,z"></div>');
8624
+ if (parent) {
8625
+ this.attachTo(parent);
8626
+ }
8627
+ this._eventBus.once('formEditor.rendered', 500, () => {
8628
+ this._render();
8629
+ });
8630
+ }
8631
+
8632
+ /**
8633
+ * Attach the properties panel to a parent node.
8634
+ *
8635
+ * @param {HTMLElement} container
8636
+ */
8637
+ attachTo(container) {
8638
+ if (!container) {
8639
+ throw new Error('container required');
8640
+ }
8641
+ if (typeof container === 'string') {
8642
+ container = query(container);
8643
+ }
8644
+
8645
+ // (1) detach from old parent
8646
+ this.detach();
8647
+
8648
+ // (2) append to parent container
8649
+ container.appendChild(this._container);
8650
+
8651
+ // (3) notify interested parties
8652
+ this._eventBus.fire('propertiesPanel.attach');
8653
+ }
8654
+
8655
+ /**
8656
+ * Detach the properties panel from its parent node.
8657
+ */
8658
+ detach() {
8659
+ const parentNode = this._container.parentNode;
8660
+ if (parentNode) {
8661
+ parentNode.removeChild(this._container);
8662
+ this._eventBus.fire('propertiesPanel.detach');
8663
+ }
8664
+ }
8665
+ _render() {
8666
+ render(jsx(FormPropertiesPanel, {
8667
+ getProviders: this._getProviders.bind(this),
8668
+ eventBus: this._eventBus,
8669
+ injector: this._injector
8670
+ }), this._container);
8671
+ this._eventBus.fire('propertiesPanel.rendered');
8672
+ }
8673
+ _destroy() {
8674
+ if (this._container) {
8675
+ render(null, this._container);
8676
+ this._eventBus.fire('propertiesPanel.destroyed');
8677
+ }
8678
+ }
8679
+
8680
+ /**
8681
+ * Register a new properties provider to the properties panel.
8682
+ *
8683
+ * @param {PropertiesProvider} provider
8684
+ * @param {Number} [priority]
8685
+ */
8686
+ registerProvider(provider, priority) {
8687
+ if (!priority) {
8688
+ priority = DEFAULT_PRIORITY;
8689
+ }
8690
+ if (typeof provider.getGroups !== 'function') {
8691
+ console.error('Properties provider does not implement #getGroups(element) API');
8692
+ return;
8693
+ }
8694
+ this._eventBus.on('propertiesPanel.getProviders', priority, function (event) {
8695
+ event.providers.push(provider);
8696
+ });
8697
+ this._eventBus.fire('propertiesPanel.providersChanged');
8698
+ }
8699
+ _getProviders() {
8700
+ const event = this._eventBus.createEvent({
8701
+ type: 'propertiesPanel.getProviders',
8702
+ providers: []
8703
+ });
8704
+ this._eventBus.fire(event);
8705
+ return event.providers;
8706
+ }
8432
8707
  }
8708
+ PropertiesPanelRenderer.$inject = ['config.propertiesPanel', 'injector', 'eventBus'];
8433
8709
 
8434
- function AltTextEntry(props) {
8710
+ function ActionEntry(props) {
8435
8711
  const {
8436
8712
  editField,
8437
8713
  field
8438
8714
  } = props;
8715
+ const entries = [];
8716
+ entries.push({
8717
+ id: 'action',
8718
+ component: Action,
8719
+ editField: editField,
8720
+ field: field,
8721
+ isEdited: isEdited$3,
8722
+ isDefaultVisible: field => field.type === 'button'
8723
+ });
8724
+ return entries;
8725
+ }
8726
+ function Action(props) {
8439
8727
  const {
8440
- type
8441
- } = field;
8728
+ editField,
8729
+ field,
8730
+ id
8731
+ } = props;
8732
+ const path = ['action'];
8733
+ const getValue = () => {
8734
+ return get(field, path, '');
8735
+ };
8736
+ const setValue = value => {
8737
+ return editField(field, path, value);
8738
+ };
8739
+ const getOptions = () => [{
8740
+ label: 'Submit',
8741
+ value: 'submit'
8742
+ }, {
8743
+ label: 'Reset',
8744
+ value: 'reset'
8745
+ }];
8746
+ return SelectEntry({
8747
+ element: field,
8748
+ getOptions,
8749
+ getValue,
8750
+ id,
8751
+ label: 'Action',
8752
+ setValue
8753
+ });
8754
+ }
8755
+
8756
+ function AltTextEntry(props) {
8757
+ const {
8758
+ editField,
8759
+ field
8760
+ } = props;
8442
8761
  const entries = [];
8443
- if (type === 'image') {
8444
- entries.push({
8445
- id: 'alt',
8446
- component: AltText,
8447
- editField: editField,
8448
- field: field,
8449
- isEdited: isEdited$6
8450
- });
8451
- }
8762
+ entries.push({
8763
+ id: 'alt',
8764
+ component: AltText,
8765
+ editField: editField,
8766
+ field: field,
8767
+ isEdited: isEdited$6,
8768
+ isDefaultVisible: field => ['image'].includes(field.type)
8769
+ });
8452
8770
  return entries;
8453
8771
  }
8454
8772
  function AltText(props) {
@@ -8559,19 +8877,15 @@ function DescriptionEntry(props) {
8559
8877
  editField,
8560
8878
  field
8561
8879
  } = props;
8562
- const {
8563
- type
8564
- } = field;
8565
8880
  const entries = [];
8566
- if (INPUTS.includes(type)) {
8567
- entries.push({
8568
- id: 'description',
8569
- component: Description,
8570
- editField: editField,
8571
- field: field,
8572
- isEdited: isEdited$6
8573
- });
8574
- }
8881
+ entries.push({
8882
+ id: 'description',
8883
+ component: Description,
8884
+ editField: editField,
8885
+ field: field,
8886
+ isEdited: isEdited$6,
8887
+ isDefaultVisible: field => INPUTS.includes(field.type)
8888
+ });
8575
8889
  return entries;
8576
8890
  }
8577
8891
  function Description(props) {
@@ -8613,10 +8927,14 @@ function DefaultOptionEntry(props) {
8613
8927
  type
8614
8928
  } = field;
8615
8929
  const entries = [];
8616
-
8617
- // Only make default values available when they are statically defined
8618
- if (!INPUTS.includes(type) || VALUES_INPUTS.includes(type) && !field.values) {
8619
- return entries;
8930
+ function isDefaultVisible(matchers) {
8931
+ return field => {
8932
+ // Only make default values available when they are statically defined
8933
+ if (!INPUTS.includes(type) || VALUES_INPUTS.includes(type) && !field.values) {
8934
+ return false;
8935
+ }
8936
+ return matchers(field);
8937
+ };
8620
8938
  }
8621
8939
  const defaultOptions = {
8622
8940
  editField,
@@ -8624,44 +8942,39 @@ function DefaultOptionEntry(props) {
8624
8942
  id: 'defaultValue',
8625
8943
  label: 'Default value'
8626
8944
  };
8627
- if (type === 'checkbox') {
8628
- entries.push({
8629
- ...defaultOptions,
8630
- component: DefaultValueCheckbox,
8631
- isEdited: isEdited$3
8632
- });
8633
- }
8634
- if (type === 'number') {
8635
- entries.push({
8636
- ...defaultOptions,
8637
- component: DefaultValueNumber,
8638
- isEdited: isEdited
8639
- });
8640
- }
8641
- if (type === 'radio' || type === 'select') {
8642
- entries.push({
8643
- ...defaultOptions,
8644
- component: DefaultValueSingleSelect,
8645
- isEdited: isEdited$3
8646
- });
8647
- }
8945
+ entries.push({
8946
+ ...defaultOptions,
8947
+ component: DefaultValueCheckbox,
8948
+ isEdited: isEdited$3,
8949
+ isDefaultVisible: isDefaultVisible(field => field.type === 'checkbox')
8950
+ });
8951
+ entries.push({
8952
+ ...defaultOptions,
8953
+ component: DefaultValueNumber,
8954
+ isEdited: isEdited,
8955
+ isDefaultVisible: isDefaultVisible(field => field.type === 'number')
8956
+ });
8957
+ entries.push({
8958
+ ...defaultOptions,
8959
+ component: DefaultValueSingleSelect,
8960
+ isEdited: isEdited$3,
8961
+ isDefaultVisible: isDefaultVisible(field => field.type === 'radio' || field.type === 'select')
8962
+ });
8648
8963
 
8649
8964
  // todo(Skaiir): implement a multiselect equivalent (cf. https://github.com/bpmn-io/form-js/issues/265)
8650
8965
 
8651
- if (type === 'textfield') {
8652
- entries.push({
8653
- ...defaultOptions,
8654
- component: DefaultValueTextfield,
8655
- isEdited: isEdited
8656
- });
8657
- }
8658
- if (type === 'textarea') {
8659
- entries.push({
8660
- ...defaultOptions,
8661
- component: DefaultValueTextarea,
8662
- isEdited: isEdited$1
8663
- });
8664
- }
8966
+ entries.push({
8967
+ ...defaultOptions,
8968
+ component: DefaultValueTextfield,
8969
+ isEdited: isEdited,
8970
+ isDefaultVisible: isDefaultVisible(field => field.type === 'textfield')
8971
+ });
8972
+ entries.push({
8973
+ ...defaultOptions,
8974
+ component: DefaultValueTextarea,
8975
+ isEdited: isEdited$1,
8976
+ isDefaultVisible: isDefaultVisible(field => field.type === 'textarea')
8977
+ });
8665
8978
  return entries;
8666
8979
  }
8667
8980
  function DefaultValueCheckbox(props) {
@@ -8846,19 +9159,15 @@ function DisabledEntry(props) {
8846
9159
  editField,
8847
9160
  field
8848
9161
  } = props;
8849
- const {
8850
- type
8851
- } = field;
8852
9162
  const entries = [];
8853
- if (INPUTS.includes(type)) {
8854
- entries.push({
8855
- id: 'disabled',
8856
- component: Disabled,
8857
- editField: editField,
8858
- field: field,
8859
- isEdited: isEdited$8
8860
- });
8861
- }
9163
+ entries.push({
9164
+ id: 'disabled',
9165
+ component: Disabled,
9166
+ editField: editField,
9167
+ field: field,
9168
+ isEdited: isEdited$8,
9169
+ isDefaultVisible: field => INPUTS.includes(field.type)
9170
+ });
8862
9171
  return entries;
8863
9172
  }
8864
9173
  function Disabled(props) {
@@ -8891,15 +9200,14 @@ function IdEntry(props) {
8891
9200
  field
8892
9201
  } = props;
8893
9202
  const entries = [];
8894
- if (field.type === 'default') {
8895
- entries.push({
8896
- id: 'id',
8897
- component: Id,
8898
- editField: editField,
8899
- field: field,
8900
- isEdited: isEdited
8901
- });
8902
- }
9203
+ entries.push({
9204
+ id: 'id',
9205
+ component: Id,
9206
+ editField: editField,
9207
+ field: field,
9208
+ isEdited: isEdited,
9209
+ isDefaultVisible: field => field.type === 'default'
9210
+ });
8903
9211
  return entries;
8904
9212
  }
8905
9213
  function Id(props) {
@@ -8970,19 +9278,15 @@ function KeyEntry(props) {
8970
9278
  editField,
8971
9279
  field
8972
9280
  } = props;
8973
- const {
8974
- type
8975
- } = field;
8976
9281
  const entries = [];
8977
- if (INPUTS.includes(type)) {
8978
- entries.push({
8979
- id: 'key',
8980
- component: Key$1,
8981
- editField: editField,
8982
- field: field,
8983
- isEdited: isEdited
8984
- });
8985
- }
9282
+ entries.push({
9283
+ id: 'key',
9284
+ component: Key$1,
9285
+ editField: editField,
9286
+ field: field,
9287
+ isEdited: isEdited,
9288
+ isDefaultVisible: field => INPUTS.includes(field.type)
9289
+ });
8986
9290
  return entries;
8987
9291
  }
8988
9292
  function Key$1(props) {
@@ -9128,7 +9432,8 @@ function simpleBoolEntryFactory(options) {
9128
9432
  label,
9129
9433
  description,
9130
9434
  path,
9131
- props
9435
+ props,
9436
+ isDefaultVisible
9132
9437
  } = options;
9133
9438
  const {
9134
9439
  editField,
@@ -9142,7 +9447,8 @@ function simpleBoolEntryFactory(options) {
9142
9447
  editField,
9143
9448
  description,
9144
9449
  component: SimpleBoolComponent,
9145
- isEdited: isEdited$5
9450
+ isEdited: isEdited$5,
9451
+ isDefaultVisible
9146
9452
  };
9147
9453
  }
9148
9454
  const SimpleBoolComponent = props => {
@@ -9190,39 +9496,35 @@ function LabelEntry(props) {
9190
9496
  field,
9191
9497
  editField
9192
9498
  } = props;
9193
- const {
9194
- type,
9195
- subtype
9196
- } = field;
9197
9499
  const entries = [];
9198
- if (type === 'datetime') {
9199
- if (subtype === DATETIME_SUBTYPES.DATE || subtype === DATETIME_SUBTYPES.DATETIME) {
9200
- entries.push({
9201
- id: 'date-label',
9202
- component: DateLabel,
9203
- editField,
9204
- field,
9205
- isEdited: isEdited$6
9206
- });
9500
+ entries.push({
9501
+ id: 'date-label',
9502
+ component: DateLabel,
9503
+ editField,
9504
+ field,
9505
+ isEdited: isEdited$6,
9506
+ isDefaultVisible: function (field) {
9507
+ return field.type === 'datetime' && (field.subtype === DATETIME_SUBTYPES.DATE || field.subtype === DATETIME_SUBTYPES.DATETIME);
9207
9508
  }
9208
- if (subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME) {
9209
- entries.push({
9210
- id: 'time-label',
9211
- component: TimeLabel,
9212
- editField,
9213
- field,
9214
- isEdited: isEdited$6
9215
- });
9509
+ });
9510
+ entries.push({
9511
+ id: 'time-label',
9512
+ component: TimeLabel,
9513
+ editField,
9514
+ field,
9515
+ isEdited: isEdited$6,
9516
+ isDefaultVisible: function (field) {
9517
+ return field.type === 'datetime' && (field.subtype === DATETIME_SUBTYPES.TIME || field.subtype === DATETIME_SUBTYPES.DATETIME);
9216
9518
  }
9217
- } else if (INPUTS.includes(type) || type === 'button' || type === 'group') {
9218
- entries.push({
9219
- id: 'label',
9220
- component: Label$1,
9221
- editField,
9222
- field,
9223
- isEdited: isEdited$6
9224
- });
9225
- }
9519
+ });
9520
+ entries.push({
9521
+ id: 'label',
9522
+ component: Label$1,
9523
+ editField,
9524
+ field,
9525
+ isEdited: isEdited$6,
9526
+ isDefaultVisible: field => INPUTS.includes(field.type) || field.type === 'button' || field.type === 'group'
9527
+ });
9226
9528
  return entries;
9227
9529
  }
9228
9530
  function Label$1(props) {
@@ -9316,19 +9618,15 @@ function SourceEntry(props) {
9316
9618
  editField,
9317
9619
  field
9318
9620
  } = props;
9319
- const {
9320
- type
9321
- } = field;
9322
9621
  const entries = [];
9323
- if (type === 'image') {
9324
- entries.push({
9325
- id: 'source',
9326
- component: Source,
9327
- editField: editField,
9328
- field: field,
9329
- isEdited: isEdited$6
9330
- });
9331
- }
9622
+ entries.push({
9623
+ id: 'source',
9624
+ component: Source,
9625
+ editField: editField,
9626
+ field: field,
9627
+ isEdited: isEdited$6,
9628
+ isDefaultVisible: field => field.type === 'image'
9629
+ });
9332
9630
  return entries;
9333
9631
  }
9334
9632
  function Source(props) {
@@ -9366,24 +9664,15 @@ function Source(props) {
9366
9664
  function TextEntry(props) {
9367
9665
  const {
9368
9666
  editField,
9369
- /* getService, */
9370
9667
  field
9371
9668
  } = props;
9372
- const {
9373
- type
9374
- } = field;
9375
-
9376
- // const templating = getService('templating');
9377
-
9378
- if (type !== 'text') {
9379
- return [];
9380
- }
9381
9669
  const entries = [{
9382
9670
  id: 'text',
9383
9671
  component: Text,
9384
9672
  editField: editField,
9385
9673
  field: field,
9386
- isEdited: isEdited$6
9674
+ isEdited: isEdited$6,
9675
+ isDefaultVisible: field => field.type === 'text'
9387
9676
  }];
9388
9677
 
9389
9678
  // todo: skipped to make the release without too much risk
@@ -9442,19 +9731,14 @@ function SpacerEntry(props) {
9442
9731
  field,
9443
9732
  id
9444
9733
  } = props;
9445
- const {
9446
- type
9447
- } = field;
9448
- if (type !== 'spacer') {
9449
- return [];
9450
- }
9451
9734
  const entries = [];
9452
9735
  entries.push({
9453
9736
  id: id + '-height',
9454
9737
  component: SpacerHeight,
9455
9738
  isEdited: isEdited$7,
9456
9739
  editField,
9457
- field
9740
+ field,
9741
+ isDefaultVisible: field => field.type === 'spacer'
9458
9742
  });
9459
9743
  return entries;
9460
9744
  }
@@ -9493,26 +9777,22 @@ function NumberEntries(props) {
9493
9777
  field,
9494
9778
  id
9495
9779
  } = props;
9496
- const {
9497
- type
9498
- } = field;
9499
- if (type !== 'number') {
9500
- return [];
9501
- }
9502
9780
  const entries = [];
9503
9781
  entries.push({
9504
9782
  id: id + '-decimalDigits',
9505
9783
  component: NumberDecimalDigits,
9506
9784
  isEdited: isEdited$7,
9507
9785
  editField,
9508
- field
9786
+ field,
9787
+ isDefaultVisible: field => field.type === 'number'
9509
9788
  });
9510
9789
  entries.push({
9511
9790
  id: id + '-step',
9512
9791
  component: NumberArrowStep,
9513
9792
  isEdited: isEdited,
9514
9793
  editField,
9515
- field
9794
+ field,
9795
+ isDefaultVisible: field => field.type === 'number'
9516
9796
  });
9517
9797
  return entries;
9518
9798
  }
@@ -9597,19 +9877,14 @@ function NumberSerializationEntry(props) {
9597
9877
  editField,
9598
9878
  field
9599
9879
  } = props;
9600
- const {
9601
- type
9602
- } = field;
9603
- if (type !== 'number') {
9604
- return [];
9605
- }
9606
9880
  const entries = [];
9607
9881
  entries.push({
9608
9882
  id: 'serialize-to-string',
9609
9883
  component: SerializeToString,
9610
9884
  isEdited: isEdited$5,
9611
9885
  editField,
9612
- field
9886
+ field,
9887
+ isDefaultVisible: field => field.type === 'number'
9613
9888
  });
9614
9889
  return entries;
9615
9890
  }
@@ -9648,29 +9923,22 @@ function DateTimeEntry(props) {
9648
9923
  editField,
9649
9924
  field
9650
9925
  } = props;
9651
- const {
9652
- type,
9653
- subtype
9654
- } = field;
9655
- if (type !== 'datetime') {
9656
- return [];
9657
- }
9658
9926
  const entries = [{
9659
9927
  id: 'subtype',
9660
9928
  component: DateTimeSubtypeSelect,
9661
9929
  isEdited: isEdited$3,
9662
9930
  editField,
9663
- field
9931
+ field,
9932
+ isDefaultVisible: field => field.type === 'datetime'
9664
9933
  }];
9665
- if (subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME) {
9666
- entries.push({
9667
- id: 'use24h',
9668
- component: Use24h,
9669
- isEdited: isEdited$5,
9670
- editField,
9671
- field
9672
- });
9673
- }
9934
+ entries.push({
9935
+ id: 'use24h',
9936
+ component: Use24h,
9937
+ isEdited: isEdited$5,
9938
+ editField,
9939
+ field,
9940
+ isDefaultVisible: field => field.type === 'datetime' && (field.subtype === DATETIME_SUBTYPES.TIME || field.subtype === DATETIME_SUBTYPES.DATETIME)
9941
+ });
9674
9942
  return entries;
9675
9943
  }
9676
9944
  function DateTimeSubtypeSelect(props) {
@@ -9758,32 +10026,31 @@ function DateTimeConstraintsEntry(props) {
9758
10026
  field,
9759
10027
  id
9760
10028
  } = props;
9761
- const {
9762
- type,
9763
- subtype
9764
- } = field;
9765
- if (type !== 'datetime') {
9766
- return [];
10029
+ function isDefaultVisible(subtypes) {
10030
+ return field => {
10031
+ if (field.type !== 'datetime') {
10032
+ return false;
10033
+ }
10034
+ return subtypes.includes(field.subtype);
10035
+ };
9767
10036
  }
9768
10037
  const entries = [];
9769
- if (subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME) {
9770
- entries.push({
9771
- id: id + '-timeInterval',
9772
- component: TimeIntervalSelect,
9773
- isEdited: isEdited$3,
9774
- editField,
9775
- field
9776
- });
9777
- }
9778
- if (subtype === DATETIME_SUBTYPES.DATE || subtype === DATETIME_SUBTYPES.DATETIME) {
9779
- entries.push({
9780
- id: id + '-disallowPassedDates',
9781
- component: DisallowPassedDates,
9782
- isEdited: isEdited$5,
9783
- editField,
9784
- field
9785
- });
9786
- }
10038
+ entries.push({
10039
+ id: id + '-timeInterval',
10040
+ component: TimeIntervalSelect,
10041
+ isEdited: isEdited$3,
10042
+ editField,
10043
+ field,
10044
+ isDefaultVisible: isDefaultVisible([DATETIME_SUBTYPES.TIME, DATETIME_SUBTYPES.DATETIME])
10045
+ });
10046
+ entries.push({
10047
+ id: id + '-disallowPassedDates',
10048
+ component: DisallowPassedDates,
10049
+ isEdited: isEdited$5,
10050
+ editField,
10051
+ field,
10052
+ isDefaultVisible: isDefaultVisible([DATETIME_SUBTYPES.DATE, DATETIME_SUBTYPES.DATETIME])
10053
+ });
9787
10054
  return entries;
9788
10055
  }
9789
10056
  function DisallowPassedDates(props) {
@@ -9837,23 +10104,15 @@ function DateTimeFormatEntry(props) {
9837
10104
  editField,
9838
10105
  field
9839
10106
  } = props;
9840
- const {
9841
- type,
9842
- subtype
9843
- } = field;
9844
- if (type !== 'datetime') {
9845
- return [];
9846
- }
9847
10107
  const entries = [];
9848
- if (subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME) {
9849
- entries.push({
9850
- id: 'time-format',
9851
- component: TimeFormatSelect,
9852
- isEdited: isEdited$3,
9853
- editField,
9854
- field
9855
- });
9856
- }
10108
+ entries.push({
10109
+ id: 'time-format',
10110
+ component: TimeFormatSelect,
10111
+ isEdited: isEdited$3,
10112
+ editField,
10113
+ field,
10114
+ isDefaultVisible: field => field.type === 'datetime' && (field.subtype === DATETIME_SUBTYPES.TIME || field.subtype === DATETIME_SUBTYPES.DATETIME)
10115
+ });
9857
10116
  return entries;
9858
10117
  }
9859
10118
  function TimeFormatSelect(props) {
@@ -9881,20 +10140,12 @@ function TimeFormatSelect(props) {
9881
10140
  }
9882
10141
 
9883
10142
  function SelectEntries(props) {
9884
- const {
9885
- field
9886
- } = props;
9887
- const {
9888
- type
9889
- } = field;
9890
- if (type !== 'select') {
9891
- return [];
9892
- }
9893
10143
  const entries = [simpleBoolEntryFactory({
9894
10144
  id: 'searchable',
9895
10145
  path: ['searchable'],
9896
10146
  label: 'Searchable',
9897
- props
10147
+ props,
10148
+ isDefaultVisible: field => field.type === 'select'
9898
10149
  })];
9899
10150
  return entries;
9900
10151
  }
@@ -10074,14 +10325,14 @@ function Value(props) {
10074
10325
 
10075
10326
  // helpers //////////
10076
10327
 
10077
- /**
10078
- * Returns copy of object with updated value.
10079
- *
10080
- * @param {Object} properties
10081
- * @param {string} key
10082
- * @param {string} value
10083
- *
10084
- * @returns {Object}
10328
+ /**
10329
+ * Returns copy of object with updated value.
10330
+ *
10331
+ * @param {Object} properties
10332
+ * @param {string} key
10333
+ * @param {string} value
10334
+ *
10335
+ * @returns {Object}
10085
10336
  */
10086
10337
  function updateValue(properties, key, value) {
10087
10338
  return {
@@ -10090,14 +10341,14 @@ function updateValue(properties, key, value) {
10090
10341
  };
10091
10342
  }
10092
10343
 
10093
- /**
10094
- * Returns copy of object with updated key.
10095
- *
10096
- * @param {Object} properties
10097
- * @param {string} oldKey
10098
- * @param {string} newKey
10099
- *
10100
- * @returns {Object}
10344
+ /**
10345
+ * Returns copy of object with updated key.
10346
+ *
10347
+ * @param {Object} properties
10348
+ * @param {string} oldKey
10349
+ * @param {string} newKey
10350
+ *
10351
+ * @returns {Object}
10101
10352
  */
10102
10353
  function updateKey(properties, oldKey, newKey) {
10103
10354
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -10339,9 +10590,6 @@ function AdornerEntry(props) {
10339
10590
  editField,
10340
10591
  field
10341
10592
  } = props;
10342
- const {
10343
- type
10344
- } = field;
10345
10593
  const entries = [];
10346
10594
  const onChange = key => {
10347
10595
  return value => {
@@ -10354,26 +10602,26 @@ function AdornerEntry(props) {
10354
10602
  return get(field, ['appearance', key]);
10355
10603
  };
10356
10604
  };
10357
- if (['number', 'textfield'].includes(type)) {
10358
- entries.push({
10359
- id: 'prefix-adorner',
10360
- component: PrefixAdorner,
10361
- isEdited: isEdited$6,
10362
- editField,
10363
- field,
10364
- onChange,
10365
- getValue
10366
- });
10367
- entries.push({
10368
- id: 'suffix-adorner',
10369
- component: SuffixAdorner,
10370
- isEdited: isEdited$6,
10371
- editField,
10372
- field,
10373
- onChange,
10374
- getValue
10375
- });
10376
- }
10605
+ entries.push({
10606
+ id: 'prefix-adorner',
10607
+ component: PrefixAdorner,
10608
+ isEdited: isEdited$6,
10609
+ editField,
10610
+ field,
10611
+ onChange,
10612
+ getValue,
10613
+ isDefaultVisible: field => ['number', 'textfield'].includes(field.type)
10614
+ });
10615
+ entries.push({
10616
+ id: 'suffix-adorner',
10617
+ component: SuffixAdorner,
10618
+ isEdited: isEdited$6,
10619
+ editField,
10620
+ field,
10621
+ onChange,
10622
+ getValue,
10623
+ isDefaultVisible: field => ['number', 'textfield'].includes(field.type)
10624
+ });
10377
10625
  return entries;
10378
10626
  }
10379
10627
  function PrefixAdorner(props) {
@@ -10427,19 +10675,15 @@ function ReadonlyEntry(props) {
10427
10675
  editField,
10428
10676
  field
10429
10677
  } = props;
10430
- const {
10431
- type
10432
- } = field;
10433
10678
  const entries = [];
10434
- if (INPUTS.includes(type)) {
10435
- entries.push({
10436
- id: 'readonly',
10437
- component: Readonly,
10438
- editField: editField,
10439
- field: field,
10440
- isEdited: isEdited$6
10441
- });
10442
- }
10679
+ entries.push({
10680
+ id: 'readonly',
10681
+ component: Readonly,
10682
+ editField: editField,
10683
+ field: field,
10684
+ isEdited: isEdited$6,
10685
+ isDefaultVisible: field => INPUTS.includes(field.type)
10686
+ });
10443
10687
  return entries;
10444
10688
  }
10445
10689
  function Readonly(props) {
@@ -10623,6 +10867,9 @@ function GeneralGroup(field, editField, getService) {
10623
10867
  field,
10624
10868
  editField
10625
10869
  })];
10870
+ if (entries.length === 0) {
10871
+ return null;
10872
+ }
10626
10873
  return {
10627
10874
  id: 'general',
10628
10875
  label: 'General',
@@ -10683,9 +10930,6 @@ function ValidationGroup(field, editField) {
10683
10930
  } = field;
10684
10931
  const validate = get(field, ['validate'], {});
10685
10932
  const isCustomValidation = [undefined, VALIDATION_TYPE_OPTIONS.custom.value].includes(validate.validationType);
10686
- if (!INPUTS.includes(type)) {
10687
- return null;
10688
- }
10689
10933
  const onChange = key => {
10690
10934
  return value => {
10691
10935
  const validate = get(field, ['validate'], {});
@@ -10703,63 +10947,62 @@ function ValidationGroup(field, editField) {
10703
10947
  getValue,
10704
10948
  field,
10705
10949
  isEdited: isEdited$5,
10706
- onChange
10950
+ onChange,
10951
+ isDefaultVisible: field => INPUTS.includes(field.type)
10707
10952
  }];
10708
- if (type === 'textfield') {
10709
- entries.push({
10710
- id: 'validationType',
10711
- component: ValidationType,
10712
- getValue,
10713
- field,
10714
- editField,
10715
- isEdited: isEdited,
10716
- onChange
10717
- });
10718
- }
10719
- if (type === 'textarea' || type === 'textfield' && isCustomValidation) {
10720
- entries.push({
10721
- id: 'minLength',
10722
- component: MinLength,
10723
- getValue,
10724
- field,
10725
- isEdited: isEdited$6,
10726
- onChange
10727
- }, {
10728
- id: 'maxLength',
10729
- component: MaxLength,
10730
- getValue,
10731
- field,
10732
- isEdited: isEdited$6,
10733
- onChange
10734
- });
10735
- }
10736
- if (type === 'textfield' && isCustomValidation) {
10737
- entries.push({
10738
- id: 'pattern',
10739
- component: Pattern,
10740
- getValue,
10741
- field,
10742
- isEdited: isEdited,
10743
- onChange
10744
- });
10745
- }
10746
- if (type === 'number') {
10747
- entries.push({
10748
- id: 'min',
10749
- component: Min,
10750
- getValue,
10751
- field,
10752
- isEdited: isEdited$6,
10753
- onChange
10754
- }, {
10755
- id: 'max',
10756
- component: Max,
10757
- getValue,
10758
- field,
10759
- isEdited: isEdited$6,
10760
- onChange
10761
- });
10762
- }
10953
+ entries.push({
10954
+ id: 'validationType',
10955
+ component: ValidationType,
10956
+ getValue,
10957
+ field,
10958
+ editField,
10959
+ isEdited: isEdited,
10960
+ onChange,
10961
+ isDefaultVisible: field => field.type === 'textfield'
10962
+ });
10963
+ entries.push({
10964
+ id: 'minLength',
10965
+ component: MinLength,
10966
+ getValue,
10967
+ field,
10968
+ isEdited: isEdited$6,
10969
+ onChange,
10970
+ isDefaultVisible: field => INPUTS.includes(field.type) && (type === 'textarea' || type === 'textfield' && isCustomValidation)
10971
+ }, {
10972
+ id: 'maxLength',
10973
+ component: MaxLength,
10974
+ getValue,
10975
+ field,
10976
+ isEdited: isEdited$6,
10977
+ onChange,
10978
+ isDefaultVisible: field => INPUTS.includes(field.type) && (type === 'textarea' || type === 'textfield' && isCustomValidation)
10979
+ });
10980
+ entries.push({
10981
+ id: 'pattern',
10982
+ component: Pattern,
10983
+ getValue,
10984
+ field,
10985
+ isEdited: isEdited,
10986
+ onChange,
10987
+ isDefaultVisible: field => INPUTS.includes(field.type) && type === 'textfield' && isCustomValidation
10988
+ });
10989
+ entries.push({
10990
+ id: 'min',
10991
+ component: Min,
10992
+ getValue,
10993
+ field,
10994
+ isEdited: isEdited$6,
10995
+ onChange,
10996
+ isDefaultVisible: field => field.type === 'number'
10997
+ }, {
10998
+ id: 'max',
10999
+ component: Max,
11000
+ getValue,
11001
+ field,
11002
+ isEdited: isEdited$6,
11003
+ onChange,
11004
+ isDefaultVisible: field => field.type === 'number'
11005
+ });
10763
11006
  return {
10764
11007
  id: 'validation',
10765
11008
  label: 'Validation',
@@ -10913,12 +11156,14 @@ function ValidationType(props) {
10913
11156
  });
10914
11157
  }
10915
11158
 
10916
- function ValuesGroups(field, editField) {
11159
+ function ValuesGroups(field, editField, getService) {
10917
11160
  const {
10918
11161
  type,
10919
11162
  id: fieldId
10920
11163
  } = field;
10921
- if (!VALUES_INPUTS.includes(type)) {
11164
+ const formFields = getService('formFields');
11165
+ const fieldDefinition = formFields.get(type).config;
11166
+ if (!VALUES_INPUTS.includes(type) && !hasValuesGroupsConfigured(fieldDefinition)) {
10922
11167
  return [];
10923
11168
  }
10924
11169
  const context = {
@@ -10927,8 +11172,8 @@ function ValuesGroups(field, editField) {
10927
11172
  };
10928
11173
  const valuesSourceId = `${fieldId}-valuesSource`;
10929
11174
 
10930
- /**
10931
- * @type {Array<Group|ListGroup>}
11175
+ /**
11176
+ * @type {Array<Group|ListGroup>}
10932
11177
  */
10933
11178
  const groups = [{
10934
11179
  id: valuesSourceId,
@@ -11049,13 +11294,13 @@ function CustomPropertiesGroup(field, editField) {
11049
11294
 
11050
11295
  // helpers //////////
11051
11296
 
11052
- /**
11053
- * Returns copy of object without key.
11054
- *
11055
- * @param {Object} properties
11056
- * @param {string} oldKey
11057
- *
11058
- * @returns {Object}
11297
+ /**
11298
+ * Returns copy of object without key.
11299
+ *
11300
+ * @param {Object} properties
11301
+ * @param {string} oldKey
11302
+ *
11303
+ * @returns {Object}
11059
11304
  */
11060
11305
  function removeKey(properties, oldKey) {
11061
11306
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -11124,158 +11369,64 @@ function ConditionGroup(field, editField) {
11124
11369
  };
11125
11370
  }
11126
11371
 
11127
- function getGroups(field, editField, getService) {
11128
- if (!field) {
11129
- return [];
11130
- }
11131
- 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), CustomPropertiesGroup(field, editField)];
11132
-
11133
- // contract: if a group returns null, it should not be displayed at all
11134
- return groups.filter(group => group !== null);
11135
- }
11136
- function FormPropertiesPanel(props) {
11137
- const {
11138
- eventBus,
11139
- injector
11140
- } = props;
11141
- const formEditor = injector.get('formEditor');
11142
- const modeling = injector.get('modeling');
11143
- const selectionModule = injector.get('selection');
11144
- const propertiesPanelConfig = injector.get('config.propertiesPanel') || {};
11145
- const {
11146
- feelPopupContainer
11147
- } = propertiesPanelConfig;
11148
- const [state, setState] = useState({
11149
- selectedFormField: selectionModule.get() || formEditor._getState().schema
11150
- });
11151
- const selectedFormField = state.selectedFormField;
11152
- const refresh = useCallback(field => {
11153
- // TODO(skaiir): rework state management, re-rendering the whole properties panel is not the way to go
11154
- // https://github.com/bpmn-io/form-js/issues/686
11155
- setState({
11156
- selectedFormField: selectionModule.get() || formEditor._getState().schema
11157
- });
11158
-
11159
- // notify interested parties on property panel updates
11160
- eventBus.fire('propertiesPanel.updated', {
11161
- formField: field
11162
- });
11163
- }, [eventBus, formEditor, selectionModule]);
11164
- useLayoutEffect(() => {
11165
- /**
11166
- * TODO(pinussilvestrus): update with actual updated element,
11167
- * once we have a proper updater/change support
11168
- */
11169
- eventBus.on('changed', refresh);
11170
- eventBus.on('import.done', refresh);
11171
- eventBus.on('selection.changed', refresh);
11172
- return () => {
11173
- eventBus.off('changed', refresh);
11174
- eventBus.off('import.done', refresh);
11175
- eventBus.off('selection.changed', refresh);
11176
- };
11177
- }, [eventBus, refresh]);
11178
- const getService = (type, strict = true) => injector.get(type, strict);
11179
- const propertiesPanelContext = {
11180
- getService
11181
- };
11182
- const onFocus = () => eventBus.fire('propertiesPanel.focusin');
11183
- const onBlur = () => eventBus.fire('propertiesPanel.focusout');
11184
- const editField = useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]);
11185
- return jsx("div", {
11186
- class: "fjs-properties-panel",
11187
- "data-field": selectedFormField && selectedFormField.id,
11188
- onFocusCapture: onFocus,
11189
- onBlurCapture: onBlur,
11190
- children: jsx(FormPropertiesPanelContext.Provider, {
11191
- value: propertiesPanelContext,
11192
- children: jsx(PropertiesPanel, {
11193
- element: selectedFormField,
11194
- eventBus: eventBus,
11195
- groups: getGroups(selectedFormField, editField, getService),
11196
- headerProvider: PropertiesPanelHeaderProvider,
11197
- placeholderProvider: PropertiesPanelPlaceholderProvider,
11198
- feelPopupContainer: feelPopupContainer
11199
- })
11200
- })
11201
- });
11202
- }
11203
-
11204
- class PropertiesPanelRenderer {
11205
- constructor(propertiesPanelConfig, injector, eventBus) {
11206
- const {
11207
- parent
11208
- } = propertiesPanelConfig || {};
11209
- this._eventBus = eventBus;
11372
+ class PropertiesProvider {
11373
+ constructor(propertiesPanel, injector) {
11210
11374
  this._injector = injector;
11211
- this._container = domify('<div class="fjs-properties-container" input-handle-modified-keys="y,z"></div>');
11212
- if (parent) {
11213
- this.attachTo(parent);
11214
- }
11215
- this._eventBus.once('formEditor.rendered', 500, () => {
11216
- this._render();
11217
- });
11375
+ propertiesPanel.registerProvider(this);
11218
11376
  }
11219
-
11220
- /**
11221
- * Attach the properties panel to a parent node.
11222
- *
11223
- * @param {HTMLElement} container
11224
- */
11225
- attachTo(container) {
11226
- if (!container) {
11227
- throw new Error('container required');
11228
- }
11229
- if (typeof container === 'string') {
11230
- container = query(container);
11231
- }
11232
-
11233
- // (1) detach from old parent
11234
- this.detach();
11235
-
11236
- // (2) append to parent container
11237
- container.appendChild(this._container);
11238
-
11239
- // (3) notify interested parties
11240
- this._eventBus.fire('propertiesPanel.attach');
11377
+ _filterVisibleEntries(groups, field, getService) {
11378
+ return groups.forEach(group => {
11379
+ const {
11380
+ entries
11381
+ } = group;
11382
+ const {
11383
+ type
11384
+ } = field;
11385
+ const formFields = getService('formFields');
11386
+ const fieldDefinition = formFields.get(type).config;
11387
+ if (!entries) {
11388
+ return;
11389
+ }
11390
+ group.entries = entries.filter(entry => {
11391
+ const {
11392
+ isDefaultVisible
11393
+ } = entry;
11394
+ if (!isDefaultVisible) {
11395
+ return true;
11396
+ }
11397
+ return isDefaultVisible(field) || hasEntryConfigured(fieldDefinition, entry.id);
11398
+ });
11399
+ });
11241
11400
  }
11401
+ getGroups(field, editField) {
11402
+ return groups => {
11403
+ if (!field) {
11404
+ return groups;
11405
+ }
11406
+ const getService = (type, strict = true) => this._injector.get(type, strict);
11407
+ groups = [...groups, GeneralGroup(field, editField, getService), ConditionGroup(field, editField), LayoutGroup(field, editField), AppearanceGroup(field, editField), SerializationGroup(field, editField), ...ValuesGroups(field, editField, getService), ConstraintsGroup(field, editField), ValidationGroup(field, editField), CustomPropertiesGroup(field, editField)].filter(group => group != null);
11408
+ this._filterVisibleEntries(groups, field, getService);
11242
11409
 
11243
- /**
11244
- * Detach the properties panel from its parent node.
11245
- */
11246
- detach() {
11247
- const parentNode = this._container.parentNode;
11248
- if (parentNode) {
11249
- parentNode.removeChild(this._container);
11250
- this._eventBus.fire('propertiesPanel.detach');
11251
- }
11252
- }
11253
- _render() {
11254
- render(jsx(FormPropertiesPanel, {
11255
- eventBus: this._eventBus,
11256
- injector: this._injector
11257
- }), this._container);
11258
- this._eventBus.fire('propertiesPanel.rendered');
11259
- }
11260
- _destroy() {
11261
- if (this._container) {
11262
- render(null, this._container);
11263
- this._eventBus.fire('propertiesPanel.destroyed');
11264
- }
11410
+ // contract: if a group has no entries or items, it should not be displayed at all
11411
+ return groups.filter(group => {
11412
+ return group.items || group.entries && group.entries.length;
11413
+ });
11414
+ };
11265
11415
  }
11266
11416
  }
11267
- PropertiesPanelRenderer.$inject = ['config.propertiesPanel', 'injector', 'eventBus'];
11417
+ PropertiesProvider.$inject = ['propertiesPanel', 'injector'];
11268
11418
 
11269
11419
  var PropertiesPanelModule = {
11270
11420
  __depends__: [index],
11271
- __init__: ['propertiesPanel'],
11272
- propertiesPanel: ['type', PropertiesPanelRenderer]
11421
+ __init__: ['propertiesPanel', 'propertiesProvider'],
11422
+ propertiesPanel: ['type', PropertiesPanelRenderer],
11423
+ propertiesProvider: ['type', PropertiesProvider]
11273
11424
  };
11274
11425
 
11275
- /**
11276
- * Manages the rendering of visual plugins.
11277
- * @constructor
11278
- * @param {Object} eventBus - Event bus for the application.
11426
+ /**
11427
+ * Manages the rendering of visual plugins.
11428
+ * @constructor
11429
+ * @param {Object} eventBus - Event bus for the application.
11279
11430
  */
11280
11431
  class RenderInjector extends SectionModuleBase {
11281
11432
  constructor(eventBus) {
@@ -11284,10 +11435,10 @@ class RenderInjector extends SectionModuleBase {
11284
11435
  this.registeredRenderers = [];
11285
11436
  }
11286
11437
 
11287
- /**
11288
- * Inject a new renderer into the injector.
11289
- * @param {string} identifier - Identifier for the renderer.
11290
- * @param {Function} Renderer - The renderer function.
11438
+ /**
11439
+ * Inject a new renderer into the injector.
11440
+ * @param {string} identifier - Identifier for the renderer.
11441
+ * @param {Function} Renderer - The renderer function.
11291
11442
  */
11292
11443
  attachRenderer(identifier, Renderer) {
11293
11444
  this.registeredRenderers = [...this.registeredRenderers, {
@@ -11296,17 +11447,17 @@ class RenderInjector extends SectionModuleBase {
11296
11447
  }];
11297
11448
  }
11298
11449
 
11299
- /**
11300
- * Detach a renderer from the by key injector.
11301
- * @param {string} identifier - Identifier for the renderer.
11450
+ /**
11451
+ * Detach a renderer from the by key injector.
11452
+ * @param {string} identifier - Identifier for the renderer.
11302
11453
  */
11303
11454
  detachRenderer(identifier) {
11304
11455
  this.registeredRenderers = this.registeredRenderers.filter(r => r.identifier !== identifier);
11305
11456
  }
11306
11457
 
11307
- /**
11308
- * Returns the registered renderers.
11309
- * @returns {Array} Array of registered renderers.
11458
+ /**
11459
+ * Returns the registered renderers.
11460
+ * @returns {Array} Array of registered renderers.
11310
11461
  */
11311
11462
  fetchRenderers() {
11312
11463
  return this.registeredRenderers;
@@ -11340,48 +11491,48 @@ var ExpressionLanguageModule = {
11340
11491
 
11341
11492
  const ids = new Ids([32, 36, 1]);
11342
11493
 
11343
- /**
11344
- * @typedef { import('./types').Injector } Injector
11345
- * @typedef { import('./types').Module } Module
11346
- * @typedef { import('./types').Schema } Schema
11347
- *
11348
- * @typedef { import('./types').FormEditorOptions } FormEditorOptions
11349
- * @typedef { import('./types').FormEditorProperties } FormEditorProperties
11350
- *
11351
- * @typedef { {
11352
- * properties: FormEditorProperties,
11353
- * schema: Schema
11354
- * } } State
11355
- *
11356
- * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
11357
- * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
11358
- * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
11494
+ /**
11495
+ * @typedef { import('./types').Injector } Injector
11496
+ * @typedef { import('./types').Module } Module
11497
+ * @typedef { import('./types').Schema } Schema
11498
+ *
11499
+ * @typedef { import('./types').FormEditorOptions } FormEditorOptions
11500
+ * @typedef { import('./types').FormEditorProperties } FormEditorProperties
11501
+ *
11502
+ * @typedef { {
11503
+ * properties: FormEditorProperties,
11504
+ * schema: Schema
11505
+ * } } State
11506
+ *
11507
+ * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
11508
+ * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
11509
+ * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
11359
11510
  */
11360
11511
 
11361
- /**
11362
- * The form editor.
11512
+ /**
11513
+ * The form editor.
11363
11514
  */
11364
11515
  class FormEditor {
11365
- /**
11366
- * @constructor
11367
- * @param {FormEditorOptions} options
11516
+ /**
11517
+ * @constructor
11518
+ * @param {FormEditorOptions} options
11368
11519
  */
11369
11520
  constructor(options = {}) {
11370
- /**
11371
- * @public
11372
- * @type {OnEventType}
11521
+ /**
11522
+ * @public
11523
+ * @type {OnEventType}
11373
11524
  */
11374
11525
  this.on = this._onEvent;
11375
11526
 
11376
- /**
11377
- * @public
11378
- * @type {String}
11527
+ /**
11528
+ * @public
11529
+ * @type {String}
11379
11530
  */
11380
11531
  this._id = ids.next();
11381
11532
 
11382
- /**
11383
- * @private
11384
- * @type {Element}
11533
+ /**
11534
+ * @private
11535
+ * @type {Element}
11385
11536
  */
11386
11537
  this._container = createFormContainer();
11387
11538
  this._container.setAttribute('input-handle-modified-keys', 'z,y');
@@ -11392,15 +11543,15 @@ class FormEditor {
11392
11543
  properties = {}
11393
11544
  } = options;
11394
11545
 
11395
- /**
11396
- * @private
11397
- * @type {any}
11546
+ /**
11547
+ * @private
11548
+ * @type {any}
11398
11549
  */
11399
11550
  this.exporter = exporter;
11400
11551
 
11401
- /**
11402
- * @private
11403
- * @type {State}
11552
+ /**
11553
+ * @private
11554
+ * @type {State}
11404
11555
  */
11405
11556
  this._state = {
11406
11557
  properties,
@@ -11429,10 +11580,10 @@ class FormEditor {
11429
11580
  this._detach(false);
11430
11581
  }
11431
11582
 
11432
- /**
11433
- * @param {Schema} schema
11434
- *
11435
- * @return {Promise<{ warnings: Array<any> }>}
11583
+ /**
11584
+ * @param {Schema} schema
11585
+ *
11586
+ * @return {Promise<{ warnings: Array<any> }>}
11436
11587
  */
11437
11588
  importSchema(schema) {
11438
11589
  return new Promise((resolve, reject) => {
@@ -11461,15 +11612,15 @@ class FormEditor {
11461
11612
  });
11462
11613
  }
11463
11614
 
11464
- /**
11465
- * @returns {Schema}
11615
+ /**
11616
+ * @returns {Schema}
11466
11617
  */
11467
11618
  saveSchema() {
11468
11619
  return this.getSchema();
11469
11620
  }
11470
11621
 
11471
- /**
11472
- * @returns {Schema}
11622
+ /**
11623
+ * @returns {Schema}
11473
11624
  */
11474
11625
  getSchema() {
11475
11626
  const {
@@ -11478,8 +11629,8 @@ class FormEditor {
11478
11629
  return exportSchema(schema, this.exporter, schemaVersion);
11479
11630
  }
11480
11631
 
11481
- /**
11482
- * @param {Element|string} parentNode
11632
+ /**
11633
+ * @param {Element|string} parentNode
11483
11634
  */
11484
11635
  attachTo(parentNode) {
11485
11636
  if (!parentNode) {
@@ -11497,10 +11648,10 @@ class FormEditor {
11497
11648
  this._detach();
11498
11649
  }
11499
11650
 
11500
- /**
11501
- * @internal
11502
- *
11503
- * @param {boolean} [emit]
11651
+ /**
11652
+ * @internal
11653
+ *
11654
+ * @param {boolean} [emit]
11504
11655
  */
11505
11656
  _detach(emit = true) {
11506
11657
  const container = this._container,
@@ -11514,9 +11665,9 @@ class FormEditor {
11514
11665
  parentNode.removeChild(container);
11515
11666
  }
11516
11667
 
11517
- /**
11518
- * @param {any} property
11519
- * @param {any} value
11668
+ /**
11669
+ * @param {any} property
11670
+ * @param {any} value
11520
11671
  */
11521
11672
  setProperty(property, value) {
11522
11673
  const properties = set$1(this._getState().properties, [property], value);
@@ -11525,21 +11676,21 @@ class FormEditor {
11525
11676
  });
11526
11677
  }
11527
11678
 
11528
- /**
11529
- * @param {string} type
11530
- * @param {Function} handler
11679
+ /**
11680
+ * @param {string} type
11681
+ * @param {Function} handler
11531
11682
  */
11532
11683
  off(type, handler) {
11533
11684
  this.get('eventBus').off(type, handler);
11534
11685
  }
11535
11686
 
11536
- /**
11537
- * @internal
11538
- *
11539
- * @param {FormEditorOptions} options
11540
- * @param {Element} container
11541
- *
11542
- * @returns {Injector}
11687
+ /**
11688
+ * @internal
11689
+ *
11690
+ * @param {FormEditorOptions} options
11691
+ * @param {Element} container
11692
+ *
11693
+ * @returns {Injector}
11543
11694
  */
11544
11695
  _createInjector(options, container) {
11545
11696
  const {
@@ -11561,22 +11712,22 @@ class FormEditor {
11561
11712
  }, core, ...modules, ...additionalModules]);
11562
11713
  }
11563
11714
 
11564
- /**
11565
- * @internal
11715
+ /**
11716
+ * @internal
11566
11717
  */
11567
11718
  _emit(type, data) {
11568
11719
  this.get('eventBus').fire(type, data);
11569
11720
  }
11570
11721
 
11571
- /**
11572
- * @internal
11722
+ /**
11723
+ * @internal
11573
11724
  */
11574
11725
  _getState() {
11575
11726
  return this._state;
11576
11727
  }
11577
11728
 
11578
- /**
11579
- * @internal
11729
+ /**
11730
+ * @internal
11580
11731
  */
11581
11732
  _setState(state) {
11582
11733
  this._state = {
@@ -11586,15 +11737,15 @@ class FormEditor {
11586
11737
  this._emit('changed', this._getState());
11587
11738
  }
11588
11739
 
11589
- /**
11590
- * @internal
11740
+ /**
11741
+ * @internal
11591
11742
  */
11592
11743
  _getModules() {
11593
11744
  return [ModelingModule, EditorActionsModule, DraggingModule, KeyboardModule, SelectionModule, PaletteModule, ExpressionLanguageModule, MarkdownModule, PropertiesPanelModule, RenderInjectionModule];
11594
11745
  }
11595
11746
 
11596
- /**
11597
- * @internal
11747
+ /**
11748
+ * @internal
11598
11749
  */
11599
11750
  _onEvent(type, priority, handler) {
11600
11751
  this.get('eventBus').on(type, priority, handler);
@@ -11642,5 +11793,5 @@ function createFormEditor(options) {
11642
11793
  });
11643
11794
  }
11644
11795
 
11645
- export { FormEditor, createFormEditor };
11796
+ export { FormEditor, createFormEditor, useDebounce, usePrevious$1 as usePrevious, useService as usePropertiesPanelService, useService$1 as useService, useVariables };
11646
11797
  //# sourceMappingURL=index.es.js.map