@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.cjs CHANGED
@@ -38,7 +38,7 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
38
38
  var focusTrap__namespace = /*#__PURE__*/_interopNamespaceDefault(focusTrap);
39
39
 
40
40
  var FN_REF = '__fn';
41
- var DEFAULT_PRIORITY$2 = 1000;
41
+ var DEFAULT_PRIORITY$3 = 1000;
42
42
  var slice = Array.prototype.slice;
43
43
 
44
44
  /**
@@ -183,7 +183,7 @@ EventBus.prototype.on = function (events, priority, callback, that) {
183
183
  if (minDash.isFunction(priority)) {
184
184
  that = callback;
185
185
  callback = priority;
186
- priority = DEFAULT_PRIORITY$2;
186
+ priority = DEFAULT_PRIORITY$3;
187
187
  }
188
188
  if (!minDash.isNumber(priority)) {
189
189
  throw new Error('priority must be a number');
@@ -222,7 +222,7 @@ EventBus.prototype.once = function (events, priority, callback, that) {
222
222
  if (minDash.isFunction(priority)) {
223
223
  that = callback;
224
224
  callback = priority;
225
- priority = DEFAULT_PRIORITY$2;
225
+ priority = DEFAULT_PRIORITY$3;
226
226
  }
227
227
  if (!minDash.isNumber(priority)) {
228
228
  throw new Error('priority must be a number');
@@ -537,10 +537,10 @@ function invokeFunction(fn, args) {
537
537
  return fn.apply(null, args);
538
538
  }
539
539
 
540
- /**
541
- * A factory to create a configurable debouncer.
542
- *
543
- * @param {number|boolean} [config=true]
540
+ /**
541
+ * A factory to create a configurable debouncer.
542
+ *
543
+ * @param {number|boolean} [config=true]
544
544
  */
545
545
  function DebounceFactory(config = true) {
546
546
  const timeout = typeof config === 'number' ? config : config ? 300 : 0;
@@ -553,11 +553,11 @@ function DebounceFactory(config = true) {
553
553
  DebounceFactory.$inject = ['config.debounce'];
554
554
 
555
555
  class FormFieldRegistry extends formJsViewer.FormFieldRegistry {
556
- /**
557
- * Updates a form fields id.
558
- *
559
- * @param {Object} formField
560
- * @param {string} newId
556
+ /**
557
+ * Updates a form fields id.
558
+ *
559
+ * @param {Object} formField
560
+ * @param {string} newId
561
561
  */
562
562
  updateId(formField, newId) {
563
563
  this._validateId(newId);
@@ -578,13 +578,13 @@ class FormFieldRegistry extends formJsViewer.FormFieldRegistry {
578
578
  }
579
579
  }
580
580
 
581
- /**
582
- * Validate the suitability of the given id and signals a problem
583
- * with an exception.
584
- *
585
- * @param {string} id
586
- *
587
- * @throws {Error} if id is empty or already assigned
581
+ /**
582
+ * Validate the suitability of the given id and signals a problem
583
+ * with an exception.
584
+ *
585
+ * @param {string} id
586
+ *
587
+ * @throws {Error} if id is empty or already assigned
588
588
  */
589
589
  _validateId(id) {
590
590
  if (!id) {
@@ -601,11 +601,11 @@ const MAX_COLUMNS = 16;
601
601
  const MIN_COLUMNS = 2;
602
602
  const MAX_FIELDS_PER_ROW = 4;
603
603
  class FormLayoutValidator {
604
- /**
605
- * @constructor
606
- *
607
- * @param { import('./FormLayouter').default } formLayouter
608
- * @param { import('./FormFieldRegistry').default } formFieldRegistry
604
+ /**
605
+ * @constructor
606
+ *
607
+ * @param { import('./FormLayouter').default } formLayouter
608
+ * @param { import('./FormFieldRegistry').default } formFieldRegistry
609
609
  */
610
610
  constructor(formLayouter, formFieldRegistry) {
611
611
  this._formLayouter = formLayouter;
@@ -676,21 +676,21 @@ function editorFormFieldClasses(type, {
676
676
  });
677
677
  }
678
678
 
679
- /**
680
- * Add a dragger that calls back the passed function with
681
- * { event, delta } on drag.
682
- *
683
- * @example
684
- *
685
- * function dragMove(event, delta) {
686
- * // we are dragging (!!)
687
- * }
688
- *
689
- * domElement.addEventListener('dragstart', dragger(dragMove));
690
- *
691
- * @param {Function} fn
692
- *
693
- * @return {Function} drag start callback function
679
+ /**
680
+ * Add a dragger that calls back the passed function with
681
+ * { event, delta } on drag.
682
+ *
683
+ * @example
684
+ *
685
+ * function dragMove(event, delta) {
686
+ * // we are dragging (!!)
687
+ * }
688
+ *
689
+ * domElement.addEventListener('dragstart', dragger(dragMove));
690
+ *
691
+ * @param {Function} fn
692
+ *
693
+ * @return {Function} drag start callback function
694
694
  */
695
695
  function createDragger$1(fn) {
696
696
  let self;
@@ -731,12 +731,12 @@ function createDragger$1(fn) {
731
731
  return onDragStart;
732
732
  }
733
733
 
734
- /**
735
- * Throttle function call according UI update cycle.
736
- *
737
- * @param {Function} fn
738
- *
739
- * @return {Function} throttled fn
734
+ /**
735
+ * Throttle function call according UI update cycle.
736
+ *
737
+ * @param {Function} fn
738
+ *
739
+ * @return {Function} throttled fn
740
740
  */
741
741
  function throttle(fn) {
742
742
  let active = false;
@@ -770,11 +770,11 @@ const DragAndDropContext = preact.createContext({
770
770
  });
771
771
  var DragAndDropContext$1 = DragAndDropContext;
772
772
 
773
- /**
774
- * @param {string} type
775
- * @param {boolean} [strict]
776
- *
777
- * @returns {any}
773
+ /**
774
+ * @param {string} type
775
+ * @param {boolean} [strict]
776
+ *
777
+ * @returns {any}
778
778
  */
779
779
  function getService$1(type, strict) {}
780
780
  const FormEditorContext = preact.createContext({
@@ -789,6 +789,27 @@ function useService$1 (type, strict) {
789
789
  return getService(type, strict);
790
790
  }
791
791
 
792
+ function usePrevious$1(value) {
793
+ const ref = hooks.useRef();
794
+ hooks.useEffect(() => ref.current = value);
795
+ return ref.current;
796
+ }
797
+
798
+ function useDebounce(fn, dependencies = []) {
799
+ const debounce = useService$1('debounce');
800
+ const callback = hooks.useMemo(() => {
801
+ return debounce(fn);
802
+ }, dependencies);
803
+
804
+ // cleanup async side-effect if callback #flush is provided.
805
+ hooks.useEffect(() => {
806
+ return () => {
807
+ typeof callback.flush === 'function' && callback.flush();
808
+ };
809
+ }, [callback]);
810
+ return callback;
811
+ }
812
+
792
813
  var _path$4;
793
814
  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); }
794
815
  var SvgClose = function SvgClose(props) {
@@ -1124,23 +1145,23 @@ var Slot = (props => {
1124
1145
  return fillsAndSeparators;
1125
1146
  });
1126
1147
 
1127
- /**
1128
- * Creates a Fragment for a fill.
1129
- *
1130
- * @param {Object} fill Fill to be rendered
1131
- * @returns {Object} Preact Fragment containing fill's children
1148
+ /**
1149
+ * Creates a Fragment for a fill.
1150
+ *
1151
+ * @param {Object} fill Fill to be rendered
1152
+ * @returns {Object} Preact Fragment containing fill's children
1132
1153
  */
1133
1154
  const FillFragment = fill => jsxRuntime.jsx(preact.Fragment, {
1134
1155
  children: fill.children
1135
1156
  }, fill.id);
1136
1157
 
1137
- /**
1138
- * Creates an array of fills, with separators inserted between groups.
1139
- *
1140
- * @param {Array} groups Groups of fills
1141
- * @param {Function} fillRenderer Function to create a fill
1142
- * @param {Function} separatorRenderer Function to create a separator
1143
- * @returns {Array} Array of fills and separators
1158
+ /**
1159
+ * Creates an array of fills, with separators inserted between groups.
1160
+ *
1161
+ * @param {Array} groups Groups of fills
1162
+ * @param {Function} fillRenderer Function to create a fill
1163
+ * @param {Function} separatorRenderer Function to create a separator
1164
+ * @returns {Array} Array of fills and separators
1144
1165
  */
1145
1166
  const buildFills = (groups, fillRenderer, separatorRenderer) => {
1146
1167
  const result = [];
@@ -1158,8 +1179,8 @@ const buildFills = (groups, fillRenderer, separatorRenderer) => {
1158
1179
  return result;
1159
1180
  };
1160
1181
 
1161
- /**
1162
- * Groups fills by group name property.
1182
+ /**
1183
+ * Groups fills by group name property.
1163
1184
  */
1164
1185
  const _groupByGroupName = fills => {
1165
1186
  const groups = [];
@@ -1179,8 +1200,8 @@ const _groupByGroupName = fills => {
1179
1200
  return Object.keys(groupsById).sort().map(id => groupsById[id]);
1180
1201
  };
1181
1202
 
1182
- /**
1183
- * Compares fills by priority.
1203
+ /**
1204
+ * Compares fills by priority.
1184
1205
  */
1185
1206
  const _comparePriority = (a, b) => {
1186
1207
  return (b.priority || 0) - (a.priority || 0);
@@ -1211,17 +1232,63 @@ var SlotFillRoot = (props => {
1211
1232
  });
1212
1233
  });
1213
1234
 
1214
- const PALETTE_ENTRIES = formJsViewer.formFields.filter(({
1215
- config: fieldConfig
1216
- }) => fieldConfig.type !== 'default').map(({
1217
- config: fieldConfig
1218
- }) => {
1219
- return {
1220
- label: fieldConfig.label,
1221
- type: fieldConfig.type,
1222
- group: fieldConfig.group
1235
+ function PaletteEntry(props) {
1236
+ const {
1237
+ type,
1238
+ label,
1239
+ icon,
1240
+ iconUrl,
1241
+ getPaletteIcon
1242
+ } = props;
1243
+ const modeling = useService$1('modeling');
1244
+ const formEditor = useService$1('formEditor');
1245
+ const Icon = getPaletteIcon({
1246
+ icon,
1247
+ iconUrl,
1248
+ label,
1249
+ type
1250
+ });
1251
+ const onKeyDown = event => {
1252
+ if (event.code === 'Enter') {
1253
+ const {
1254
+ fieldType: type
1255
+ } = event.target.dataset;
1256
+ const {
1257
+ schema
1258
+ } = formEditor._getState();
1259
+
1260
+ // add new form field to last position
1261
+ modeling.addFormField({
1262
+ type
1263
+ }, schema, schema.components.length);
1264
+ }
1223
1265
  };
1224
- });
1266
+ return jsxRuntime.jsxs("button", {
1267
+ class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
1268
+ "data-field-type": type,
1269
+ title: `Create ${getIndefiniteArticle(type)} ${label} element`,
1270
+ onKeyDown: onKeyDown,
1271
+ children: [Icon ? jsxRuntime.jsx(Icon, {
1272
+ class: "fjs-palette-field-icon",
1273
+ width: "36",
1274
+ height: "36",
1275
+ viewBox: "0 0 54 54"
1276
+ }) : null, jsxRuntime.jsx("span", {
1277
+ class: "fjs-palette-field-text",
1278
+ children: label
1279
+ })]
1280
+ });
1281
+ }
1282
+
1283
+ // helpers ///////////
1284
+
1285
+ function getIndefiniteArticle(type) {
1286
+ if (['image'].includes(type)) {
1287
+ return 'an';
1288
+ }
1289
+ return 'a';
1290
+ }
1291
+
1225
1292
  const PALETTE_GROUPS = [{
1226
1293
  label: 'Basic input',
1227
1294
  id: 'basic-input'
@@ -1236,10 +1303,12 @@ const PALETTE_GROUPS = [{
1236
1303
  id: 'action'
1237
1304
  }];
1238
1305
  function Palette(props) {
1239
- const [entries, setEntries] = hooks.useState(PALETTE_ENTRIES);
1306
+ const formFields = useService$1('formFields');
1307
+ const initialPaletteEntries = hooks.useRef(collectPaletteEntries(formFields));
1308
+ const [paletteEntries, setPaletteEntries] = hooks.useState(initialPaletteEntries.current);
1240
1309
  const [searchTerm, setSearchTerm] = hooks.useState('');
1241
1310
  const inputRef = hooks.useRef();
1242
- const groups = groupEntries(entries);
1311
+ const groups = groupEntries(paletteEntries);
1243
1312
  const simplifyString = hooks.useCallback(str => {
1244
1313
  return str.toLowerCase().replace(/\s+/g, '');
1245
1314
  }, []);
@@ -1255,8 +1324,8 @@ function Palette(props) {
1255
1324
 
1256
1325
  // filter entries on search change
1257
1326
  hooks.useEffect(() => {
1258
- const entries = PALETTE_ENTRIES.filter(filter);
1259
- setEntries(entries);
1327
+ const entries = initialPaletteEntries.current.filter(filter);
1328
+ setPaletteEntries(entries);
1260
1329
  }, [filter, searchTerm]);
1261
1330
  const handleInput = hooks.useCallback(event => {
1262
1331
  setSearchTerm(() => event.target.value);
@@ -1303,24 +1372,10 @@ function Palette(props) {
1303
1372
  children: label
1304
1373
  }), jsxRuntime.jsx("div", {
1305
1374
  class: "fjs-palette-fields fjs-drag-container fjs-no-drop",
1306
- children: entries.map(({
1307
- label,
1308
- type
1309
- }) => {
1310
- const Icon = formJsViewer.iconsByType(type);
1311
- return jsxRuntime.jsxs("div", {
1312
- class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
1313
- "data-field-type": type,
1314
- title: `Create ${getIndefiniteArticle(type)} ${label} element`,
1315
- children: [Icon ? jsxRuntime.jsx(Icon, {
1316
- class: "fjs-palette-field-icon",
1317
- width: "36",
1318
- height: "36",
1319
- viewBox: "0 0 54 54"
1320
- }) : null, jsxRuntime.jsx("span", {
1321
- class: "fjs-palette-field-text",
1322
- children: label
1323
- })]
1375
+ children: entries.map(entry => {
1376
+ return jsxRuntime.jsx(PaletteEntry, {
1377
+ getPaletteIcon: getPaletteIcon,
1378
+ ...entry
1324
1379
  });
1325
1380
  })
1326
1381
  })]
@@ -1360,11 +1415,59 @@ function groupEntries(entries) {
1360
1415
  });
1361
1416
  return groups.filter(g => g.entries.length);
1362
1417
  }
1363
- function getIndefiniteArticle(type) {
1364
- if (['image'].includes(type)) {
1365
- return 'an';
1418
+
1419
+ /**
1420
+ * Returns a list of palette entries.
1421
+ *
1422
+ * @param {FormFields} formFields
1423
+ * @returns {Array<PaletteEntry>}
1424
+ */
1425
+ function collectPaletteEntries(formFields) {
1426
+ return Object.entries(formFields._formFields).map(([type, formField]) => {
1427
+ const {
1428
+ config: fieldConfig
1429
+ } = formField;
1430
+ return {
1431
+ label: fieldConfig.label,
1432
+ type: type,
1433
+ group: fieldConfig.group,
1434
+ icon: fieldConfig.icon,
1435
+ iconUrl: fieldConfig.iconUrl
1436
+ };
1437
+ }).filter(({
1438
+ type
1439
+ }) => type !== 'default');
1440
+ }
1441
+
1442
+ /**
1443
+ * There are various options to specify an icon for a palette entry.
1444
+ *
1445
+ * a) via `iconUrl` property in a form field config
1446
+ * b) via `icon` property in a form field config
1447
+ * c) via statically defined iconsByType (fallback)
1448
+ */
1449
+ function getPaletteIcon(entry) {
1450
+ const {
1451
+ icon,
1452
+ iconUrl,
1453
+ type,
1454
+ label
1455
+ } = entry;
1456
+ let Icon;
1457
+ if (iconUrl) {
1458
+ Icon = () => jsxRuntime.jsx("img", {
1459
+ class: "fjs-field-icon-image",
1460
+ width: 36,
1461
+ style: {
1462
+ margin: 'auto'
1463
+ },
1464
+ alt: label,
1465
+ src: formJsViewer.sanitizeImageSource(iconUrl)
1466
+ });
1467
+ } else {
1468
+ Icon = icon || formJsViewer.iconsByType(type);
1366
1469
  }
1367
- return 'a';
1470
+ return Icon;
1368
1471
  }
1369
1472
 
1370
1473
  var InjectedRendersRoot = (() => {
@@ -1408,20 +1511,20 @@ const DRAG_NO_DROP_CLS = 'fjs-no-drop';
1408
1511
  const DRAG_NO_MOVE_CLS = 'fjs-no-move';
1409
1512
  const ERROR_DROP_CLS = 'fjs-error-drop';
1410
1513
 
1411
- /**
1412
- * @typedef { { id: String, components: Array<any> } } FormRow
1514
+ /**
1515
+ * @typedef { { id: String, components: Array<any> } } FormRow
1413
1516
  */
1414
1517
 
1415
1518
  class Dragging {
1416
- /**
1417
- * @constructor
1418
- *
1419
- * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1420
- * @param { import('../../core/FormLayouter').default } formLayouter
1421
- * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1422
- * @param { import('../../core/EventBus').default } eventBus
1423
- * @param { import('../modeling/Modeling').default } modeling
1424
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
1519
+ /**
1520
+ * @constructor
1521
+ *
1522
+ * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1523
+ * @param { import('../../core/FormLayouter').default } formLayouter
1524
+ * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1525
+ * @param { import('../../core/EventBus').default } eventBus
1526
+ * @param { import('../modeling/Modeling').default } modeling
1527
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
1425
1528
  */
1426
1529
  constructor(formFieldRegistry, formLayouter, formLayoutValidator, eventBus, modeling, pathRegistry) {
1427
1530
  this._formFieldRegistry = formFieldRegistry;
@@ -1432,13 +1535,13 @@ class Dragging {
1432
1535
  this._pathRegistry = pathRegistry;
1433
1536
  }
1434
1537
 
1435
- /**
1436
- * Calculcates position in form schema given the dropped place.
1437
- *
1438
- * @param { FormRow } targetRow
1439
- * @param { any } targetFormField
1440
- * @param { HTMLElement } sibling
1441
- * @returns { number }
1538
+ /**
1539
+ * Calculcates position in form schema given the dropped place.
1540
+ *
1541
+ * @param { FormRow } targetRow
1542
+ * @param { any } targetFormField
1543
+ * @param { HTMLElement } sibling
1544
+ * @returns { number }
1442
1545
  */
1443
1546
  getTargetIndex(targetRow, targetFormField, sibling) {
1444
1547
  /** @type HTMLElement */
@@ -1579,8 +1682,8 @@ class Dragging {
1579
1682
  }
1580
1683
  }
1581
1684
 
1582
- /**
1583
- * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1685
+ /**
1686
+ * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1584
1687
  */
1585
1688
  createDragulaInstance(options) {
1586
1689
  const {
@@ -1994,7 +2097,7 @@ function DebugColumns(props) {
1994
2097
  return null;
1995
2098
  }
1996
2099
  return jsxRuntime.jsx("div", {
1997
- 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;",
2100
+ 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;",
1998
2101
  class: "fjs-debug-columns",
1999
2102
  children: (field.layout || {}).columns || 'auto'
2000
2103
  });
@@ -2134,6 +2237,9 @@ function FormEditor$1(props) {
2134
2237
 
2135
2238
  // fire event after render to notify interested parties
2136
2239
  hooks.useEffect(() => {
2240
+ eventBus.fire('rendered');
2241
+
2242
+ // keep deprecated event to ensure backward compatibility
2137
2243
  eventBus.fire('formEditor.rendered');
2138
2244
  }, []);
2139
2245
  const [hoveredId, setHoveredId] = hooks.useState(null);
@@ -2229,15 +2335,20 @@ function CreatePreview(props) {
2229
2335
  const {
2230
2336
  drake
2231
2337
  } = hooks.useContext(DragAndDropContext$1);
2338
+ const formFields = useService$1('formFields');
2232
2339
  function handleCloned(clone, original, type) {
2233
2340
  const fieldType = clone.dataset.fieldType;
2234
2341
 
2235
2342
  // (1) field preview
2236
2343
  if (fieldType) {
2344
+ const paletteEntry = findPaletteEntry(fieldType, formFields);
2345
+ if (!paletteEntry) {
2346
+ return;
2347
+ }
2237
2348
  const {
2238
2349
  label
2239
- } = findPaletteEntry(fieldType);
2240
- const Icon = formJsViewer.iconsByType(fieldType);
2350
+ } = paletteEntry;
2351
+ const Icon = getPaletteIcon(paletteEntry);
2241
2352
  clone.innerHTML = '';
2242
2353
  clone.class = 'gu-mirror';
2243
2354
  clone.classList.add('fjs-field-preview-container');
@@ -2278,8 +2389,8 @@ function CreatePreview(props) {
2278
2389
 
2279
2390
  // helper //////
2280
2391
 
2281
- function findPaletteEntry(type) {
2282
- return PALETTE_ENTRIES.find(entry => entry.type === type);
2392
+ function findPaletteEntry(type, formFields) {
2393
+ return collectPaletteEntries(formFields).find(entry => entry.type === type);
2283
2394
  }
2284
2395
  function defaultPropertiesPanel(propertiesPanelConfig) {
2285
2396
  return !(propertiesPanelConfig && propertiesPanelConfig.parent);
@@ -2694,7 +2805,7 @@ function isRedo(event) {
2694
2805
  var KEYDOWN_EVENT = 'keyboard.keydown',
2695
2806
  KEYUP_EVENT = 'keyboard.keyup';
2696
2807
  var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
2697
- var DEFAULT_PRIORITY$1 = 1000;
2808
+ var DEFAULT_PRIORITY$2 = 1000;
2698
2809
 
2699
2810
  /**
2700
2811
  * A keyboard abstraction that may be activated and
@@ -2827,7 +2938,7 @@ Keyboard.prototype.addListener = function (priority, listener, type) {
2827
2938
  if (minDash.isFunction(priority)) {
2828
2939
  type = listener;
2829
2940
  listener = priority;
2830
- priority = DEFAULT_PRIORITY$1;
2941
+ priority = DEFAULT_PRIORITY$2;
2831
2942
  }
2832
2943
  this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
2833
2944
  };
@@ -3065,10 +3176,10 @@ function updateRow(formField, rowId) {
3065
3176
  }
3066
3177
 
3067
3178
  class AddFormFieldHandler {
3068
- /**
3069
- * @constructor
3070
- * @param { import('../../../FormEditor').default } formEditor
3071
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3179
+ /**
3180
+ * @constructor
3181
+ * @param { import('../../../FormEditor').default } formEditor
3182
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3072
3183
  */
3073
3184
  constructor(formEditor, formFieldRegistry) {
3074
3185
  this._formEditor = formEditor;
@@ -3129,10 +3240,10 @@ class AddFormFieldHandler {
3129
3240
  AddFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3130
3241
 
3131
3242
  class EditFormFieldHandler {
3132
- /**
3133
- * @constructor
3134
- * @param { import('../../../FormEditor').default } formEditor
3135
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3243
+ /**
3244
+ * @constructor
3245
+ * @param { import('../../../FormEditor').default } formEditor
3246
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3136
3247
  */
3137
3248
  constructor(formEditor, formFieldRegistry) {
3138
3249
  this._formEditor = formEditor;
@@ -3195,11 +3306,11 @@ class EditFormFieldHandler {
3195
3306
  EditFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3196
3307
 
3197
3308
  class MoveFormFieldHandler {
3198
- /**
3199
- * @constructor
3200
- * @param { import('../../../FormEditor').default } formEditor
3201
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3202
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3309
+ /**
3310
+ * @constructor
3311
+ * @param { import('../../../FormEditor').default } formEditor
3312
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3313
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3203
3314
  */
3204
3315
  constructor(formEditor, formFieldRegistry, pathRegistry) {
3205
3316
  this._formEditor = formEditor;
@@ -3304,10 +3415,10 @@ class MoveFormFieldHandler {
3304
3415
  MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry', 'pathRegistry'];
3305
3416
 
3306
3417
  class RemoveFormFieldHandler {
3307
- /**
3308
- * @constructor
3309
- * @param { import('../../../FormEditor').default } formEditor
3310
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3418
+ /**
3419
+ * @constructor
3420
+ * @param { import('../../../FormEditor').default } formEditor
3421
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3311
3422
  */
3312
3423
  constructor(formEditor, formFieldRegistry) {
3313
3424
  this._formEditor = formEditor;
@@ -3367,9 +3478,9 @@ class RemoveFormFieldHandler {
3367
3478
  RemoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3368
3479
 
3369
3480
  class UpdateIdClaimHandler {
3370
- /**
3371
- * @constructor
3372
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3481
+ /**
3482
+ * @constructor
3483
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3373
3484
  */
3374
3485
  constructor(formFieldRegistry) {
3375
3486
  this._formFieldRegistry = formFieldRegistry;
@@ -3402,9 +3513,9 @@ class UpdateIdClaimHandler {
3402
3513
  UpdateIdClaimHandler.$inject = ['formFieldRegistry'];
3403
3514
 
3404
3515
  class UpdateKeyClaimHandler {
3405
- /**
3406
- * @constructor
3407
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3516
+ /**
3517
+ * @constructor
3518
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3408
3519
  */
3409
3520
  constructor(pathRegistry) {
3410
3521
  this._pathRegistry = pathRegistry;
@@ -3445,9 +3556,9 @@ class UpdateKeyClaimHandler {
3445
3556
  UpdateKeyClaimHandler.$inject = ['pathRegistry'];
3446
3557
 
3447
3558
  class UpdatePathClaimHandler {
3448
- /**
3449
- * @constructor
3450
- * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3559
+ /**
3560
+ * @constructor
3561
+ * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3451
3562
  */
3452
3563
  constructor(pathRegistry) {
3453
3564
  this._pathRegistry = pathRegistry;
@@ -3645,7 +3756,7 @@ Modeling.$inject = ['commandStack', 'eventBus', 'formEditor', 'formFieldRegistry
3645
3756
  * @typedef { (context: CommandContext) => void } ComposeHandlerFunction
3646
3757
  */
3647
3758
 
3648
- var DEFAULT_PRIORITY = 1000;
3759
+ var DEFAULT_PRIORITY$1 = 1000;
3649
3760
 
3650
3761
  /**
3651
3762
  * A utility that can be used to plug into the command execution for
@@ -3706,7 +3817,7 @@ CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, u
3706
3817
  that = unwrap;
3707
3818
  unwrap = handlerFn;
3708
3819
  handlerFn = priority;
3709
- priority = DEFAULT_PRIORITY;
3820
+ priority = DEFAULT_PRIORITY$1;
3710
3821
  }
3711
3822
  if (minDash.isObject(unwrap)) {
3712
3823
  that = unwrap;
@@ -4009,8 +4120,8 @@ class ValidateBehavior extends CommandInterceptor {
4009
4120
  constructor(eventBus) {
4010
4121
  super(eventBus);
4011
4122
 
4012
- /**
4013
- * Remove custom validation if <validationType> is about to be added.
4123
+ /**
4124
+ * Remove custom validation if <validationType> is about to be added.
4014
4125
  */
4015
4126
  this.preExecute('formField.edit', function (context) {
4016
4127
  const {
@@ -4590,22 +4701,22 @@ var SelectionModule = {
4590
4701
  selectionBehavior: ['type', SelectionBehavior]
4591
4702
  };
4592
4703
 
4593
- /**
4594
- * Base class for sectionable UI modules.
4595
- *
4596
- * @property {EventBus} _eventBus - EventBus instance used for event handling.
4597
- * @property {string} managerType - Type of the render manager. Used to form event names.
4598
- *
4599
- * @class SectionModuleBase
4704
+ /**
4705
+ * Base class for sectionable UI modules.
4706
+ *
4707
+ * @property {EventBus} _eventBus - EventBus instance used for event handling.
4708
+ * @property {string} managerType - Type of the render manager. Used to form event names.
4709
+ *
4710
+ * @class SectionModuleBase
4600
4711
  */
4601
4712
  class SectionModuleBase {
4602
- /**
4603
- * Create a SectionModuleBase instance.
4604
- *
4605
- * @param {any} eventBus - The EventBus instance used for event handling.
4606
- * @param {string} sectionKey - The type of render manager. Used to form event names.
4607
- *
4608
- * @constructor
4713
+ /**
4714
+ * Create a SectionModuleBase instance.
4715
+ *
4716
+ * @param {any} eventBus - The EventBus instance used for event handling.
4717
+ * @param {string} sectionKey - The type of render manager. Used to form event names.
4718
+ *
4719
+ * @constructor
4609
4720
  */
4610
4721
  constructor(eventBus, sectionKey) {
4611
4722
  this._eventBus = eventBus;
@@ -4618,10 +4729,10 @@ class SectionModuleBase {
4618
4729
  });
4619
4730
  }
4620
4731
 
4621
- /**
4622
- * Attach the managed section to a parent node.
4623
- *
4624
- * @param {HTMLElement} container - The parent node to attach to.
4732
+ /**
4733
+ * Attach the managed section to a parent node.
4734
+ *
4735
+ * @param {HTMLElement} container - The parent node to attach to.
4625
4736
  */
4626
4737
  attachTo(container) {
4627
4738
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.attach`, {
@@ -4629,22 +4740,22 @@ class SectionModuleBase {
4629
4740
  }));
4630
4741
  }
4631
4742
 
4632
- /**
4633
- * Detach the managed section from its parent node.
4743
+ /**
4744
+ * Detach the managed section from its parent node.
4634
4745
  */
4635
4746
  detach() {
4636
4747
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.detach`));
4637
4748
  }
4638
4749
 
4639
- /**
4640
- * Reset the managed section to its initial state.
4750
+ /**
4751
+ * Reset the managed section to its initial state.
4641
4752
  */
4642
4753
  reset() {
4643
4754
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.reset`));
4644
4755
  }
4645
4756
 
4646
- /**
4647
- * Circumvents timing issues.
4757
+ /**
4758
+ * Circumvents timing issues.
4648
4759
  */
4649
4760
  _onceSectionRendered(callback) {
4650
4761
  if (this.isSectionRendered) {
@@ -5778,6 +5889,7 @@ function PopupComponent(props, globalRef) {
5778
5889
  const focusTrapRef = hooks.useRef(null);
5779
5890
  const localRef = hooks.useRef(null);
5780
5891
  const popupRef = globalRef || localRef;
5892
+ const containerNode = hooks.useMemo(() => getContainerNode(container), [container]);
5781
5893
  const handleKeydown = event => {
5782
5894
  // do not allow keyboard events to bubble
5783
5895
  event.stopPropagation();
@@ -5837,7 +5949,7 @@ function PopupComponent(props, globalRef) {
5837
5949
  class: classnames('bio-properties-panel-popup', className),
5838
5950
  style: style,
5839
5951
  children: props.children
5840
- }), container || document.body);
5952
+ }), containerNode || document.body);
5841
5953
  }
5842
5954
  const Popup = React.forwardRef(PopupComponent);
5843
5955
  Popup.Title = Title;
@@ -5957,6 +6069,12 @@ function cancel(event) {
5957
6069
  event.preventDefault();
5958
6070
  event.stopPropagation();
5959
6071
  }
6072
+ function getContainerNode(node) {
6073
+ if (typeof node === 'string') {
6074
+ return minDom.query(node);
6075
+ }
6076
+ return node;
6077
+ }
5960
6078
  const FEEL_POPUP_WIDTH = 700;
5961
6079
  const FEEL_POPUP_HEIGHT = 250;
5962
6080
 
@@ -6504,7 +6622,7 @@ function FeelTextfield(props) {
6504
6622
  }, [onInput, debounce]);
6505
6623
  const setLocalValue = newValue => {
6506
6624
  _setLocalValue(newValue);
6507
- if (!newValue || newValue === '=') {
6625
+ if (typeof newValue === 'undefined' || newValue === '' || newValue === '=') {
6508
6626
  handleInputCallback(undefined);
6509
6627
  } else {
6510
6628
  handleInputCallback(newValue);
@@ -8266,11 +8384,11 @@ var index = {
8266
8384
  feelPopup: ['type', FeelPopupModule]
8267
8385
  };
8268
8386
 
8269
- /**
8270
- * @param {string} type
8271
- * @param {boolean} [strict]
8272
- *
8273
- * @returns {any}
8387
+ /**
8388
+ * @param {string} type
8389
+ * @param {boolean} [strict]
8390
+ *
8391
+ * @returns {any}
8274
8392
  */
8275
8393
  function getService(type, strict) {}
8276
8394
  const PropertiesPanelContext = preact.createContext({
@@ -8308,25 +8426,43 @@ function isValidDotPath(path) {
8308
8426
  }
8309
8427
  const INPUTS = ['checkbox', 'checklist', 'datetime', 'number', 'radio', 'select', 'taglist', 'textfield', 'textarea'];
8310
8428
  const VALUES_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
8429
+ function hasEntryConfigured(formFieldDefinition, entryId) {
8430
+ const {
8431
+ propertiesPanelEntries = []
8432
+ } = formFieldDefinition;
8433
+ if (!propertiesPanelEntries.length) {
8434
+ return false;
8435
+ }
8436
+ return propertiesPanelEntries.some(id => id === entryId);
8437
+ }
8438
+ function hasValuesGroupsConfigured(formFieldDefinition) {
8439
+ const {
8440
+ propertiesPanelEntries = []
8441
+ } = formFieldDefinition;
8442
+ if (!propertiesPanelEntries.length) {
8443
+ return false;
8444
+ }
8445
+ return propertiesPanelEntries.some(id => id === 'values');
8446
+ }
8447
+
8448
+ function useService (type, strict) {
8449
+ const {
8450
+ getService
8451
+ } = hooks.useContext(FormPropertiesPanelContext);
8452
+ return getService(type, strict);
8453
+ }
8454
+
8455
+ /**
8456
+ * Retrieve list of variables from the form schema.
8457
+ *
8458
+ * @returns { string[] } list of variables used in form schema
8459
+ */
8460
+ function useVariables() {
8461
+ const form = useService('formEditor');
8462
+ const schema = form.getSchema();
8463
+ return formJsViewer.getSchemaVariables(schema);
8464
+ }
8311
8465
 
8312
- const labelsByType = {
8313
- button: 'BUTTON',
8314
- checkbox: 'CHECKBOX',
8315
- checklist: 'CHECKLIST',
8316
- columns: 'COLUMNS',
8317
- default: 'FORM',
8318
- datetime: 'DATETIME',
8319
- group: 'GROUP',
8320
- image: 'IMAGE VIEW',
8321
- number: 'NUMBER',
8322
- radio: 'RADIO',
8323
- select: 'SELECT',
8324
- spacer: 'SPACER',
8325
- taglist: 'TAGLIST',
8326
- text: 'TEXT VIEW',
8327
- textfield: 'TEXT FIELD',
8328
- textarea: 'TEXT AREA'
8329
- };
8330
8466
  const PropertiesPanelHeaderProvider = {
8331
8467
  getElementLabel: field => {
8332
8468
  const {
@@ -8350,25 +8486,43 @@ const PropertiesPanelHeaderProvider = {
8350
8486
  const {
8351
8487
  type
8352
8488
  } = field;
8353
- const Icon = formJsViewer.iconsByType(type);
8489
+
8490
+ // @Note: We know that we are inside the properties panel context,
8491
+ // so we can savely use the hook here.
8492
+ // eslint-disable-next-line react-hooks/rules-of-hooks
8493
+ const fieldDefinition = useService('formFields').get(type).config;
8494
+ const Icon = fieldDefinition.icon || formJsViewer.iconsByType(type);
8354
8495
  if (Icon) {
8355
8496
  return () => jsxRuntime.jsx(Icon, {
8356
8497
  width: "36",
8357
8498
  height: "36",
8358
8499
  viewBox: "0 0 54 54"
8359
8500
  });
8501
+ } else if (fieldDefinition.iconUrl) {
8502
+ return getPaletteIcon({
8503
+ iconUrl: fieldDefinition.iconUrl,
8504
+ label: fieldDefinition.label
8505
+ });
8360
8506
  }
8361
8507
  },
8362
8508
  getTypeLabel: field => {
8363
8509
  const {
8364
8510
  type
8365
8511
  } = field;
8366
- return labelsByType[type];
8512
+ if (type === 'default') {
8513
+ return 'Form';
8514
+ }
8515
+
8516
+ // @Note: We know that we are inside the properties panel context,
8517
+ // so we can savely use the hook here.
8518
+ // eslint-disable-next-line react-hooks/rules-of-hooks
8519
+ const fieldDefinition = useService('formFields').get(type).config;
8520
+ return fieldDefinition.label || type;
8367
8521
  }
8368
8522
  };
8369
8523
 
8370
- /**
8371
- * Provide placeholders for empty and multiple state.
8524
+ /**
8525
+ * Provide placeholders for empty and multiple state.
8372
8526
  */
8373
8527
  const PropertiesPanelPlaceholderProvider = {
8374
8528
  getEmpty: () => {
@@ -8383,92 +8537,256 @@ const PropertiesPanelPlaceholderProvider = {
8383
8537
  }
8384
8538
  };
8385
8539
 
8386
- function ActionEntry(props) {
8540
+ function FormPropertiesPanel(props) {
8387
8541
  const {
8388
- editField,
8389
- field
8542
+ eventBus,
8543
+ getProviders,
8544
+ injector
8390
8545
  } = props;
8546
+ const formEditor = injector.get('formEditor');
8547
+ const modeling = injector.get('modeling');
8548
+ const selectionModule = injector.get('selection');
8549
+ const propertiesPanelConfig = injector.get('config.propertiesPanel') || {};
8391
8550
  const {
8392
- type
8393
- } = field;
8394
- const entries = [];
8395
- if (type === 'button') {
8396
- entries.push({
8397
- id: 'action',
8398
- component: Action,
8399
- editField: editField,
8400
- field: field,
8401
- isEdited: isEdited$3
8402
- });
8403
- }
8404
- return entries;
8405
- }
8406
- function Action(props) {
8407
- const {
8408
- editField,
8409
- field,
8410
- id
8411
- } = props;
8412
- const path = ['action'];
8413
- const getValue = () => {
8414
- return minDash.get(field, path, '');
8415
- };
8416
- const setValue = value => {
8417
- return editField(field, path, value);
8418
- };
8419
- const getOptions = () => [{
8420
- label: 'Submit',
8421
- value: 'submit'
8422
- }, {
8423
- label: 'Reset',
8424
- value: 'reset'
8425
- }];
8426
- return SelectEntry({
8427
- element: field,
8428
- getOptions,
8429
- getValue,
8430
- id,
8431
- label: 'Action',
8432
- setValue
8551
+ feelPopupContainer
8552
+ } = propertiesPanelConfig;
8553
+ const [state, setState] = hooks.useState({
8554
+ selectedFormField: selectionModule.get() || formEditor._getState().schema
8433
8555
  });
8434
- }
8435
-
8436
- function useService (type, strict) {
8437
- const {
8556
+ const selectedFormField = state.selectedFormField;
8557
+ const refresh = hooks.useCallback(field => {
8558
+ // TODO(skaiir): rework state management, re-rendering the whole properties panel is not the way to go
8559
+ // https://github.com/bpmn-io/form-js/issues/686
8560
+ setState({
8561
+ selectedFormField: selectionModule.get() || formEditor._getState().schema
8562
+ });
8563
+
8564
+ // notify interested parties on property panel updates
8565
+ eventBus.fire('propertiesPanel.updated', {
8566
+ formField: field
8567
+ });
8568
+ }, [eventBus, formEditor, selectionModule]);
8569
+ hooks.useLayoutEffect(() => {
8570
+ /**
8571
+ * TODO(pinussilvestrus): update with actual updated element,
8572
+ * once we have a proper updater/change support
8573
+ */
8574
+ eventBus.on('changed', refresh);
8575
+ eventBus.on('import.done', refresh);
8576
+ eventBus.on('selection.changed', refresh);
8577
+ return () => {
8578
+ eventBus.off('changed', refresh);
8579
+ eventBus.off('import.done', refresh);
8580
+ eventBus.off('selection.changed', refresh);
8581
+ };
8582
+ }, [eventBus, refresh]);
8583
+ const getService = (type, strict = true) => injector.get(type, strict);
8584
+ const propertiesPanelContext = {
8438
8585
  getService
8439
- } = hooks.useContext(FormPropertiesPanelContext);
8440
- return getService(type, strict);
8586
+ };
8587
+ const onFocus = () => eventBus.fire('propertiesPanel.focusin');
8588
+ const onBlur = () => eventBus.fire('propertiesPanel.focusout');
8589
+ const editField = hooks.useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]);
8590
+
8591
+ // retrieve groups for selected form field
8592
+ const providers = getProviders(selectedFormField);
8593
+ const groups = hooks.useMemo(() => {
8594
+ return minDash.reduce(providers, function (groups, provider) {
8595
+ // do not collect groups for multi element state
8596
+ if (minDash.isArray(selectedFormField)) {
8597
+ return [];
8598
+ }
8599
+ const updater = provider.getGroups(selectedFormField, editField);
8600
+ return updater(groups);
8601
+ }, []);
8602
+ }, [providers, selectedFormField, editField]);
8603
+ return jsxRuntime.jsx("div", {
8604
+ class: "fjs-properties-panel",
8605
+ "data-field": selectedFormField && selectedFormField.id,
8606
+ onFocusCapture: onFocus,
8607
+ onBlurCapture: onBlur,
8608
+ children: jsxRuntime.jsx(FormPropertiesPanelContext.Provider, {
8609
+ value: propertiesPanelContext,
8610
+ children: jsxRuntime.jsx(PropertiesPanel, {
8611
+ element: selectedFormField,
8612
+ eventBus: eventBus,
8613
+ groups: groups,
8614
+ headerProvider: PropertiesPanelHeaderProvider,
8615
+ placeholderProvider: PropertiesPanelPlaceholderProvider,
8616
+ feelPopupContainer: feelPopupContainer
8617
+ })
8618
+ })
8619
+ });
8441
8620
  }
8442
8621
 
8443
- /**
8444
- * Retrieve list of variables from the form schema.
8445
- *
8446
- * @returns { string[] } list of variables used in form schema
8622
+ const DEFAULT_PRIORITY = 1000;
8623
+
8624
+ /**
8625
+ * @typedef { { parent: Element } } PropertiesPanelConfig
8626
+ * @typedef { import('../../core/EventBus').default } EventBus
8627
+ * @typedef { import('../../types').Injector } Injector
8628
+ * @typedef { { getGroups: ({ formField, editFormField }) => ({ groups}) => Array } } PropertiesProvider
8447
8629
  */
8448
- function useVariables() {
8449
- const form = useService('formEditor');
8450
- const schema = form.getSchema();
8451
- return formJsViewer.getSchemaVariables(schema);
8630
+
8631
+ /**
8632
+ * @param {PropertiesPanelConfig} propertiesPanelConfig
8633
+ * @param {Injector} injector
8634
+ * @param {EventBus} eventBus
8635
+ */
8636
+ class PropertiesPanelRenderer {
8637
+ constructor(propertiesPanelConfig, injector, eventBus) {
8638
+ const {
8639
+ parent
8640
+ } = propertiesPanelConfig || {};
8641
+ this._eventBus = eventBus;
8642
+ this._injector = injector;
8643
+ this._container = minDom.domify('<div class="fjs-properties-container" input-handle-modified-keys="y,z"></div>');
8644
+ if (parent) {
8645
+ this.attachTo(parent);
8646
+ }
8647
+ this._eventBus.once('formEditor.rendered', 500, () => {
8648
+ this._render();
8649
+ });
8650
+ }
8651
+
8652
+ /**
8653
+ * Attach the properties panel to a parent node.
8654
+ *
8655
+ * @param {HTMLElement} container
8656
+ */
8657
+ attachTo(container) {
8658
+ if (!container) {
8659
+ throw new Error('container required');
8660
+ }
8661
+ if (typeof container === 'string') {
8662
+ container = minDom.query(container);
8663
+ }
8664
+
8665
+ // (1) detach from old parent
8666
+ this.detach();
8667
+
8668
+ // (2) append to parent container
8669
+ container.appendChild(this._container);
8670
+
8671
+ // (3) notify interested parties
8672
+ this._eventBus.fire('propertiesPanel.attach');
8673
+ }
8674
+
8675
+ /**
8676
+ * Detach the properties panel from its parent node.
8677
+ */
8678
+ detach() {
8679
+ const parentNode = this._container.parentNode;
8680
+ if (parentNode) {
8681
+ parentNode.removeChild(this._container);
8682
+ this._eventBus.fire('propertiesPanel.detach');
8683
+ }
8684
+ }
8685
+ _render() {
8686
+ preact.render(jsxRuntime.jsx(FormPropertiesPanel, {
8687
+ getProviders: this._getProviders.bind(this),
8688
+ eventBus: this._eventBus,
8689
+ injector: this._injector
8690
+ }), this._container);
8691
+ this._eventBus.fire('propertiesPanel.rendered');
8692
+ }
8693
+ _destroy() {
8694
+ if (this._container) {
8695
+ preact.render(null, this._container);
8696
+ this._eventBus.fire('propertiesPanel.destroyed');
8697
+ }
8698
+ }
8699
+
8700
+ /**
8701
+ * Register a new properties provider to the properties panel.
8702
+ *
8703
+ * @param {PropertiesProvider} provider
8704
+ * @param {Number} [priority]
8705
+ */
8706
+ registerProvider(provider, priority) {
8707
+ if (!priority) {
8708
+ priority = DEFAULT_PRIORITY;
8709
+ }
8710
+ if (typeof provider.getGroups !== 'function') {
8711
+ console.error('Properties provider does not implement #getGroups(element) API');
8712
+ return;
8713
+ }
8714
+ this._eventBus.on('propertiesPanel.getProviders', priority, function (event) {
8715
+ event.providers.push(provider);
8716
+ });
8717
+ this._eventBus.fire('propertiesPanel.providersChanged');
8718
+ }
8719
+ _getProviders() {
8720
+ const event = this._eventBus.createEvent({
8721
+ type: 'propertiesPanel.getProviders',
8722
+ providers: []
8723
+ });
8724
+ this._eventBus.fire(event);
8725
+ return event.providers;
8726
+ }
8452
8727
  }
8728
+ PropertiesPanelRenderer.$inject = ['config.propertiesPanel', 'injector', 'eventBus'];
8453
8729
 
8454
- function AltTextEntry(props) {
8730
+ function ActionEntry(props) {
8455
8731
  const {
8456
8732
  editField,
8457
8733
  field
8458
8734
  } = props;
8735
+ const entries = [];
8736
+ entries.push({
8737
+ id: 'action',
8738
+ component: Action,
8739
+ editField: editField,
8740
+ field: field,
8741
+ isEdited: isEdited$3,
8742
+ isDefaultVisible: field => field.type === 'button'
8743
+ });
8744
+ return entries;
8745
+ }
8746
+ function Action(props) {
8459
8747
  const {
8460
- type
8461
- } = field;
8748
+ editField,
8749
+ field,
8750
+ id
8751
+ } = props;
8752
+ const path = ['action'];
8753
+ const getValue = () => {
8754
+ return minDash.get(field, path, '');
8755
+ };
8756
+ const setValue = value => {
8757
+ return editField(field, path, value);
8758
+ };
8759
+ const getOptions = () => [{
8760
+ label: 'Submit',
8761
+ value: 'submit'
8762
+ }, {
8763
+ label: 'Reset',
8764
+ value: 'reset'
8765
+ }];
8766
+ return SelectEntry({
8767
+ element: field,
8768
+ getOptions,
8769
+ getValue,
8770
+ id,
8771
+ label: 'Action',
8772
+ setValue
8773
+ });
8774
+ }
8775
+
8776
+ function AltTextEntry(props) {
8777
+ const {
8778
+ editField,
8779
+ field
8780
+ } = props;
8462
8781
  const entries = [];
8463
- if (type === 'image') {
8464
- entries.push({
8465
- id: 'alt',
8466
- component: AltText,
8467
- editField: editField,
8468
- field: field,
8469
- isEdited: isEdited$6
8470
- });
8471
- }
8782
+ entries.push({
8783
+ id: 'alt',
8784
+ component: AltText,
8785
+ editField: editField,
8786
+ field: field,
8787
+ isEdited: isEdited$6,
8788
+ isDefaultVisible: field => ['image'].includes(field.type)
8789
+ });
8472
8790
  return entries;
8473
8791
  }
8474
8792
  function AltText(props) {
@@ -8579,19 +8897,15 @@ function DescriptionEntry(props) {
8579
8897
  editField,
8580
8898
  field
8581
8899
  } = props;
8582
- const {
8583
- type
8584
- } = field;
8585
8900
  const entries = [];
8586
- if (INPUTS.includes(type)) {
8587
- entries.push({
8588
- id: 'description',
8589
- component: Description,
8590
- editField: editField,
8591
- field: field,
8592
- isEdited: isEdited$6
8593
- });
8594
- }
8901
+ entries.push({
8902
+ id: 'description',
8903
+ component: Description,
8904
+ editField: editField,
8905
+ field: field,
8906
+ isEdited: isEdited$6,
8907
+ isDefaultVisible: field => INPUTS.includes(field.type)
8908
+ });
8595
8909
  return entries;
8596
8910
  }
8597
8911
  function Description(props) {
@@ -8633,10 +8947,14 @@ function DefaultOptionEntry(props) {
8633
8947
  type
8634
8948
  } = field;
8635
8949
  const entries = [];
8636
-
8637
- // Only make default values available when they are statically defined
8638
- if (!INPUTS.includes(type) || VALUES_INPUTS.includes(type) && !field.values) {
8639
- return entries;
8950
+ function isDefaultVisible(matchers) {
8951
+ return field => {
8952
+ // Only make default values available when they are statically defined
8953
+ if (!INPUTS.includes(type) || VALUES_INPUTS.includes(type) && !field.values) {
8954
+ return false;
8955
+ }
8956
+ return matchers(field);
8957
+ };
8640
8958
  }
8641
8959
  const defaultOptions = {
8642
8960
  editField,
@@ -8644,44 +8962,39 @@ function DefaultOptionEntry(props) {
8644
8962
  id: 'defaultValue',
8645
8963
  label: 'Default value'
8646
8964
  };
8647
- if (type === 'checkbox') {
8648
- entries.push({
8649
- ...defaultOptions,
8650
- component: DefaultValueCheckbox,
8651
- isEdited: isEdited$3
8652
- });
8653
- }
8654
- if (type === 'number') {
8655
- entries.push({
8656
- ...defaultOptions,
8657
- component: DefaultValueNumber,
8658
- isEdited: isEdited
8659
- });
8660
- }
8661
- if (type === 'radio' || type === 'select') {
8662
- entries.push({
8663
- ...defaultOptions,
8664
- component: DefaultValueSingleSelect,
8665
- isEdited: isEdited$3
8666
- });
8667
- }
8965
+ entries.push({
8966
+ ...defaultOptions,
8967
+ component: DefaultValueCheckbox,
8968
+ isEdited: isEdited$3,
8969
+ isDefaultVisible: isDefaultVisible(field => field.type === 'checkbox')
8970
+ });
8971
+ entries.push({
8972
+ ...defaultOptions,
8973
+ component: DefaultValueNumber,
8974
+ isEdited: isEdited,
8975
+ isDefaultVisible: isDefaultVisible(field => field.type === 'number')
8976
+ });
8977
+ entries.push({
8978
+ ...defaultOptions,
8979
+ component: DefaultValueSingleSelect,
8980
+ isEdited: isEdited$3,
8981
+ isDefaultVisible: isDefaultVisible(field => field.type === 'radio' || field.type === 'select')
8982
+ });
8668
8983
 
8669
8984
  // todo(Skaiir): implement a multiselect equivalent (cf. https://github.com/bpmn-io/form-js/issues/265)
8670
8985
 
8671
- if (type === 'textfield') {
8672
- entries.push({
8673
- ...defaultOptions,
8674
- component: DefaultValueTextfield,
8675
- isEdited: isEdited
8676
- });
8677
- }
8678
- if (type === 'textarea') {
8679
- entries.push({
8680
- ...defaultOptions,
8681
- component: DefaultValueTextarea,
8682
- isEdited: isEdited$1
8683
- });
8684
- }
8986
+ entries.push({
8987
+ ...defaultOptions,
8988
+ component: DefaultValueTextfield,
8989
+ isEdited: isEdited,
8990
+ isDefaultVisible: isDefaultVisible(field => field.type === 'textfield')
8991
+ });
8992
+ entries.push({
8993
+ ...defaultOptions,
8994
+ component: DefaultValueTextarea,
8995
+ isEdited: isEdited$1,
8996
+ isDefaultVisible: isDefaultVisible(field => field.type === 'textarea')
8997
+ });
8685
8998
  return entries;
8686
8999
  }
8687
9000
  function DefaultValueCheckbox(props) {
@@ -8866,19 +9179,15 @@ function DisabledEntry(props) {
8866
9179
  editField,
8867
9180
  field
8868
9181
  } = props;
8869
- const {
8870
- type
8871
- } = field;
8872
9182
  const entries = [];
8873
- if (INPUTS.includes(type)) {
8874
- entries.push({
8875
- id: 'disabled',
8876
- component: Disabled,
8877
- editField: editField,
8878
- field: field,
8879
- isEdited: isEdited$8
8880
- });
8881
- }
9183
+ entries.push({
9184
+ id: 'disabled',
9185
+ component: Disabled,
9186
+ editField: editField,
9187
+ field: field,
9188
+ isEdited: isEdited$8,
9189
+ isDefaultVisible: field => INPUTS.includes(field.type)
9190
+ });
8882
9191
  return entries;
8883
9192
  }
8884
9193
  function Disabled(props) {
@@ -8911,15 +9220,14 @@ function IdEntry(props) {
8911
9220
  field
8912
9221
  } = props;
8913
9222
  const entries = [];
8914
- if (field.type === 'default') {
8915
- entries.push({
8916
- id: 'id',
8917
- component: Id,
8918
- editField: editField,
8919
- field: field,
8920
- isEdited: isEdited
8921
- });
8922
- }
9223
+ entries.push({
9224
+ id: 'id',
9225
+ component: Id,
9226
+ editField: editField,
9227
+ field: field,
9228
+ isEdited: isEdited,
9229
+ isDefaultVisible: field => field.type === 'default'
9230
+ });
8923
9231
  return entries;
8924
9232
  }
8925
9233
  function Id(props) {
@@ -8990,19 +9298,15 @@ function KeyEntry(props) {
8990
9298
  editField,
8991
9299
  field
8992
9300
  } = props;
8993
- const {
8994
- type
8995
- } = field;
8996
9301
  const entries = [];
8997
- if (INPUTS.includes(type)) {
8998
- entries.push({
8999
- id: 'key',
9000
- component: Key$1,
9001
- editField: editField,
9002
- field: field,
9003
- isEdited: isEdited
9004
- });
9005
- }
9302
+ entries.push({
9303
+ id: 'key',
9304
+ component: Key$1,
9305
+ editField: editField,
9306
+ field: field,
9307
+ isEdited: isEdited,
9308
+ isDefaultVisible: field => INPUTS.includes(field.type)
9309
+ });
9006
9310
  return entries;
9007
9311
  }
9008
9312
  function Key$1(props) {
@@ -9148,7 +9452,8 @@ function simpleBoolEntryFactory(options) {
9148
9452
  label,
9149
9453
  description,
9150
9454
  path,
9151
- props
9455
+ props,
9456
+ isDefaultVisible
9152
9457
  } = options;
9153
9458
  const {
9154
9459
  editField,
@@ -9162,7 +9467,8 @@ function simpleBoolEntryFactory(options) {
9162
9467
  editField,
9163
9468
  description,
9164
9469
  component: SimpleBoolComponent,
9165
- isEdited: isEdited$5
9470
+ isEdited: isEdited$5,
9471
+ isDefaultVisible
9166
9472
  };
9167
9473
  }
9168
9474
  const SimpleBoolComponent = props => {
@@ -9210,39 +9516,35 @@ function LabelEntry(props) {
9210
9516
  field,
9211
9517
  editField
9212
9518
  } = props;
9213
- const {
9214
- type,
9215
- subtype
9216
- } = field;
9217
9519
  const entries = [];
9218
- if (type === 'datetime') {
9219
- if (subtype === formJsViewer.DATETIME_SUBTYPES.DATE || subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME) {
9220
- entries.push({
9221
- id: 'date-label',
9222
- component: DateLabel,
9223
- editField,
9224
- field,
9225
- isEdited: isEdited$6
9226
- });
9520
+ entries.push({
9521
+ id: 'date-label',
9522
+ component: DateLabel,
9523
+ editField,
9524
+ field,
9525
+ isEdited: isEdited$6,
9526
+ isDefaultVisible: function (field) {
9527
+ return field.type === 'datetime' && (field.subtype === formJsViewer.DATETIME_SUBTYPES.DATE || field.subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME);
9227
9528
  }
9228
- if (subtype === formJsViewer.DATETIME_SUBTYPES.TIME || subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME) {
9229
- entries.push({
9230
- id: 'time-label',
9231
- component: TimeLabel,
9232
- editField,
9233
- field,
9234
- isEdited: isEdited$6
9235
- });
9529
+ });
9530
+ entries.push({
9531
+ id: 'time-label',
9532
+ component: TimeLabel,
9533
+ editField,
9534
+ field,
9535
+ isEdited: isEdited$6,
9536
+ isDefaultVisible: function (field) {
9537
+ return field.type === 'datetime' && (field.subtype === formJsViewer.DATETIME_SUBTYPES.TIME || field.subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME);
9236
9538
  }
9237
- } else if (INPUTS.includes(type) || type === 'button' || type === 'group') {
9238
- entries.push({
9239
- id: 'label',
9240
- component: Label$1,
9241
- editField,
9242
- field,
9243
- isEdited: isEdited$6
9244
- });
9245
- }
9539
+ });
9540
+ entries.push({
9541
+ id: 'label',
9542
+ component: Label$1,
9543
+ editField,
9544
+ field,
9545
+ isEdited: isEdited$6,
9546
+ isDefaultVisible: field => INPUTS.includes(field.type) || field.type === 'button' || field.type === 'group'
9547
+ });
9246
9548
  return entries;
9247
9549
  }
9248
9550
  function Label$1(props) {
@@ -9336,19 +9638,15 @@ function SourceEntry(props) {
9336
9638
  editField,
9337
9639
  field
9338
9640
  } = props;
9339
- const {
9340
- type
9341
- } = field;
9342
9641
  const entries = [];
9343
- if (type === 'image') {
9344
- entries.push({
9345
- id: 'source',
9346
- component: Source,
9347
- editField: editField,
9348
- field: field,
9349
- isEdited: isEdited$6
9350
- });
9351
- }
9642
+ entries.push({
9643
+ id: 'source',
9644
+ component: Source,
9645
+ editField: editField,
9646
+ field: field,
9647
+ isEdited: isEdited$6,
9648
+ isDefaultVisible: field => field.type === 'image'
9649
+ });
9352
9650
  return entries;
9353
9651
  }
9354
9652
  function Source(props) {
@@ -9386,24 +9684,15 @@ function Source(props) {
9386
9684
  function TextEntry(props) {
9387
9685
  const {
9388
9686
  editField,
9389
- /* getService, */
9390
9687
  field
9391
9688
  } = props;
9392
- const {
9393
- type
9394
- } = field;
9395
-
9396
- // const templating = getService('templating');
9397
-
9398
- if (type !== 'text') {
9399
- return [];
9400
- }
9401
9689
  const entries = [{
9402
9690
  id: 'text',
9403
9691
  component: Text,
9404
9692
  editField: editField,
9405
9693
  field: field,
9406
- isEdited: isEdited$6
9694
+ isEdited: isEdited$6,
9695
+ isDefaultVisible: field => field.type === 'text'
9407
9696
  }];
9408
9697
 
9409
9698
  // todo: skipped to make the release without too much risk
@@ -9462,19 +9751,14 @@ function SpacerEntry(props) {
9462
9751
  field,
9463
9752
  id
9464
9753
  } = props;
9465
- const {
9466
- type
9467
- } = field;
9468
- if (type !== 'spacer') {
9469
- return [];
9470
- }
9471
9754
  const entries = [];
9472
9755
  entries.push({
9473
9756
  id: id + '-height',
9474
9757
  component: SpacerHeight,
9475
9758
  isEdited: isEdited$7,
9476
9759
  editField,
9477
- field
9760
+ field,
9761
+ isDefaultVisible: field => field.type === 'spacer'
9478
9762
  });
9479
9763
  return entries;
9480
9764
  }
@@ -9513,26 +9797,22 @@ function NumberEntries(props) {
9513
9797
  field,
9514
9798
  id
9515
9799
  } = props;
9516
- const {
9517
- type
9518
- } = field;
9519
- if (type !== 'number') {
9520
- return [];
9521
- }
9522
9800
  const entries = [];
9523
9801
  entries.push({
9524
9802
  id: id + '-decimalDigits',
9525
9803
  component: NumberDecimalDigits,
9526
9804
  isEdited: isEdited$7,
9527
9805
  editField,
9528
- field
9806
+ field,
9807
+ isDefaultVisible: field => field.type === 'number'
9529
9808
  });
9530
9809
  entries.push({
9531
9810
  id: id + '-step',
9532
9811
  component: NumberArrowStep,
9533
9812
  isEdited: isEdited,
9534
9813
  editField,
9535
- field
9814
+ field,
9815
+ isDefaultVisible: field => field.type === 'number'
9536
9816
  });
9537
9817
  return entries;
9538
9818
  }
@@ -9617,19 +9897,14 @@ function NumberSerializationEntry(props) {
9617
9897
  editField,
9618
9898
  field
9619
9899
  } = props;
9620
- const {
9621
- type
9622
- } = field;
9623
- if (type !== 'number') {
9624
- return [];
9625
- }
9626
9900
  const entries = [];
9627
9901
  entries.push({
9628
9902
  id: 'serialize-to-string',
9629
9903
  component: SerializeToString,
9630
9904
  isEdited: isEdited$5,
9631
9905
  editField,
9632
- field
9906
+ field,
9907
+ isDefaultVisible: field => field.type === 'number'
9633
9908
  });
9634
9909
  return entries;
9635
9910
  }
@@ -9668,29 +9943,22 @@ function DateTimeEntry(props) {
9668
9943
  editField,
9669
9944
  field
9670
9945
  } = props;
9671
- const {
9672
- type,
9673
- subtype
9674
- } = field;
9675
- if (type !== 'datetime') {
9676
- return [];
9677
- }
9678
9946
  const entries = [{
9679
9947
  id: 'subtype',
9680
9948
  component: DateTimeSubtypeSelect,
9681
9949
  isEdited: isEdited$3,
9682
9950
  editField,
9683
- field
9951
+ field,
9952
+ isDefaultVisible: field => field.type === 'datetime'
9684
9953
  }];
9685
- if (subtype === formJsViewer.DATETIME_SUBTYPES.TIME || subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME) {
9686
- entries.push({
9687
- id: 'use24h',
9688
- component: Use24h,
9689
- isEdited: isEdited$5,
9690
- editField,
9691
- field
9692
- });
9693
- }
9954
+ entries.push({
9955
+ id: 'use24h',
9956
+ component: Use24h,
9957
+ isEdited: isEdited$5,
9958
+ editField,
9959
+ field,
9960
+ isDefaultVisible: field => field.type === 'datetime' && (field.subtype === formJsViewer.DATETIME_SUBTYPES.TIME || field.subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME)
9961
+ });
9694
9962
  return entries;
9695
9963
  }
9696
9964
  function DateTimeSubtypeSelect(props) {
@@ -9778,32 +10046,31 @@ function DateTimeConstraintsEntry(props) {
9778
10046
  field,
9779
10047
  id
9780
10048
  } = props;
9781
- const {
9782
- type,
9783
- subtype
9784
- } = field;
9785
- if (type !== 'datetime') {
9786
- return [];
10049
+ function isDefaultVisible(subtypes) {
10050
+ return field => {
10051
+ if (field.type !== 'datetime') {
10052
+ return false;
10053
+ }
10054
+ return subtypes.includes(field.subtype);
10055
+ };
9787
10056
  }
9788
10057
  const entries = [];
9789
- if (subtype === formJsViewer.DATETIME_SUBTYPES.TIME || subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME) {
9790
- entries.push({
9791
- id: id + '-timeInterval',
9792
- component: TimeIntervalSelect,
9793
- isEdited: isEdited$3,
9794
- editField,
9795
- field
9796
- });
9797
- }
9798
- if (subtype === formJsViewer.DATETIME_SUBTYPES.DATE || subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME) {
9799
- entries.push({
9800
- id: id + '-disallowPassedDates',
9801
- component: DisallowPassedDates,
9802
- isEdited: isEdited$5,
9803
- editField,
9804
- field
9805
- });
9806
- }
10058
+ entries.push({
10059
+ id: id + '-timeInterval',
10060
+ component: TimeIntervalSelect,
10061
+ isEdited: isEdited$3,
10062
+ editField,
10063
+ field,
10064
+ isDefaultVisible: isDefaultVisible([formJsViewer.DATETIME_SUBTYPES.TIME, formJsViewer.DATETIME_SUBTYPES.DATETIME])
10065
+ });
10066
+ entries.push({
10067
+ id: id + '-disallowPassedDates',
10068
+ component: DisallowPassedDates,
10069
+ isEdited: isEdited$5,
10070
+ editField,
10071
+ field,
10072
+ isDefaultVisible: isDefaultVisible([formJsViewer.DATETIME_SUBTYPES.DATE, formJsViewer.DATETIME_SUBTYPES.DATETIME])
10073
+ });
9807
10074
  return entries;
9808
10075
  }
9809
10076
  function DisallowPassedDates(props) {
@@ -9857,23 +10124,15 @@ function DateTimeFormatEntry(props) {
9857
10124
  editField,
9858
10125
  field
9859
10126
  } = props;
9860
- const {
9861
- type,
9862
- subtype
9863
- } = field;
9864
- if (type !== 'datetime') {
9865
- return [];
9866
- }
9867
10127
  const entries = [];
9868
- if (subtype === formJsViewer.DATETIME_SUBTYPES.TIME || subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME) {
9869
- entries.push({
9870
- id: 'time-format',
9871
- component: TimeFormatSelect,
9872
- isEdited: isEdited$3,
9873
- editField,
9874
- field
9875
- });
9876
- }
10128
+ entries.push({
10129
+ id: 'time-format',
10130
+ component: TimeFormatSelect,
10131
+ isEdited: isEdited$3,
10132
+ editField,
10133
+ field,
10134
+ isDefaultVisible: field => field.type === 'datetime' && (field.subtype === formJsViewer.DATETIME_SUBTYPES.TIME || field.subtype === formJsViewer.DATETIME_SUBTYPES.DATETIME)
10135
+ });
9877
10136
  return entries;
9878
10137
  }
9879
10138
  function TimeFormatSelect(props) {
@@ -9901,20 +10160,12 @@ function TimeFormatSelect(props) {
9901
10160
  }
9902
10161
 
9903
10162
  function SelectEntries(props) {
9904
- const {
9905
- field
9906
- } = props;
9907
- const {
9908
- type
9909
- } = field;
9910
- if (type !== 'select') {
9911
- return [];
9912
- }
9913
10163
  const entries = [simpleBoolEntryFactory({
9914
10164
  id: 'searchable',
9915
10165
  path: ['searchable'],
9916
10166
  label: 'Searchable',
9917
- props
10167
+ props,
10168
+ isDefaultVisible: field => field.type === 'select'
9918
10169
  })];
9919
10170
  return entries;
9920
10171
  }
@@ -10094,14 +10345,14 @@ function Value(props) {
10094
10345
 
10095
10346
  // helpers //////////
10096
10347
 
10097
- /**
10098
- * Returns copy of object with updated value.
10099
- *
10100
- * @param {Object} properties
10101
- * @param {string} key
10102
- * @param {string} value
10103
- *
10104
- * @returns {Object}
10348
+ /**
10349
+ * Returns copy of object with updated value.
10350
+ *
10351
+ * @param {Object} properties
10352
+ * @param {string} key
10353
+ * @param {string} value
10354
+ *
10355
+ * @returns {Object}
10105
10356
  */
10106
10357
  function updateValue(properties, key, value) {
10107
10358
  return {
@@ -10110,14 +10361,14 @@ function updateValue(properties, key, value) {
10110
10361
  };
10111
10362
  }
10112
10363
 
10113
- /**
10114
- * Returns copy of object with updated key.
10115
- *
10116
- * @param {Object} properties
10117
- * @param {string} oldKey
10118
- * @param {string} newKey
10119
- *
10120
- * @returns {Object}
10364
+ /**
10365
+ * Returns copy of object with updated key.
10366
+ *
10367
+ * @param {Object} properties
10368
+ * @param {string} oldKey
10369
+ * @param {string} newKey
10370
+ *
10371
+ * @returns {Object}
10121
10372
  */
10122
10373
  function updateKey(properties, oldKey, newKey) {
10123
10374
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -10359,9 +10610,6 @@ function AdornerEntry(props) {
10359
10610
  editField,
10360
10611
  field
10361
10612
  } = props;
10362
- const {
10363
- type
10364
- } = field;
10365
10613
  const entries = [];
10366
10614
  const onChange = key => {
10367
10615
  return value => {
@@ -10374,26 +10622,26 @@ function AdornerEntry(props) {
10374
10622
  return minDash.get(field, ['appearance', key]);
10375
10623
  };
10376
10624
  };
10377
- if (['number', 'textfield'].includes(type)) {
10378
- entries.push({
10379
- id: 'prefix-adorner',
10380
- component: PrefixAdorner,
10381
- isEdited: isEdited$6,
10382
- editField,
10383
- field,
10384
- onChange,
10385
- getValue
10386
- });
10387
- entries.push({
10388
- id: 'suffix-adorner',
10389
- component: SuffixAdorner,
10390
- isEdited: isEdited$6,
10391
- editField,
10392
- field,
10393
- onChange,
10394
- getValue
10395
- });
10396
- }
10625
+ entries.push({
10626
+ id: 'prefix-adorner',
10627
+ component: PrefixAdorner,
10628
+ isEdited: isEdited$6,
10629
+ editField,
10630
+ field,
10631
+ onChange,
10632
+ getValue,
10633
+ isDefaultVisible: field => ['number', 'textfield'].includes(field.type)
10634
+ });
10635
+ entries.push({
10636
+ id: 'suffix-adorner',
10637
+ component: SuffixAdorner,
10638
+ isEdited: isEdited$6,
10639
+ editField,
10640
+ field,
10641
+ onChange,
10642
+ getValue,
10643
+ isDefaultVisible: field => ['number', 'textfield'].includes(field.type)
10644
+ });
10397
10645
  return entries;
10398
10646
  }
10399
10647
  function PrefixAdorner(props) {
@@ -10447,19 +10695,15 @@ function ReadonlyEntry(props) {
10447
10695
  editField,
10448
10696
  field
10449
10697
  } = props;
10450
- const {
10451
- type
10452
- } = field;
10453
10698
  const entries = [];
10454
- if (INPUTS.includes(type)) {
10455
- entries.push({
10456
- id: 'readonly',
10457
- component: Readonly,
10458
- editField: editField,
10459
- field: field,
10460
- isEdited: isEdited$6
10461
- });
10462
- }
10699
+ entries.push({
10700
+ id: 'readonly',
10701
+ component: Readonly,
10702
+ editField: editField,
10703
+ field: field,
10704
+ isEdited: isEdited$6,
10705
+ isDefaultVisible: field => INPUTS.includes(field.type)
10706
+ });
10463
10707
  return entries;
10464
10708
  }
10465
10709
  function Readonly(props) {
@@ -10643,6 +10887,9 @@ function GeneralGroup(field, editField, getService) {
10643
10887
  field,
10644
10888
  editField
10645
10889
  })];
10890
+ if (entries.length === 0) {
10891
+ return null;
10892
+ }
10646
10893
  return {
10647
10894
  id: 'general',
10648
10895
  label: 'General',
@@ -10703,9 +10950,6 @@ function ValidationGroup(field, editField) {
10703
10950
  } = field;
10704
10951
  const validate = minDash.get(field, ['validate'], {});
10705
10952
  const isCustomValidation = [undefined, VALIDATION_TYPE_OPTIONS.custom.value].includes(validate.validationType);
10706
- if (!INPUTS.includes(type)) {
10707
- return null;
10708
- }
10709
10953
  const onChange = key => {
10710
10954
  return value => {
10711
10955
  const validate = minDash.get(field, ['validate'], {});
@@ -10723,63 +10967,62 @@ function ValidationGroup(field, editField) {
10723
10967
  getValue,
10724
10968
  field,
10725
10969
  isEdited: isEdited$5,
10726
- onChange
10970
+ onChange,
10971
+ isDefaultVisible: field => INPUTS.includes(field.type)
10727
10972
  }];
10728
- if (type === 'textfield') {
10729
- entries.push({
10730
- id: 'validationType',
10731
- component: ValidationType,
10732
- getValue,
10733
- field,
10734
- editField,
10735
- isEdited: isEdited,
10736
- onChange
10737
- });
10738
- }
10739
- if (type === 'textarea' || type === 'textfield' && isCustomValidation) {
10740
- entries.push({
10741
- id: 'minLength',
10742
- component: MinLength,
10743
- getValue,
10744
- field,
10745
- isEdited: isEdited$6,
10746
- onChange
10747
- }, {
10748
- id: 'maxLength',
10749
- component: MaxLength,
10750
- getValue,
10751
- field,
10752
- isEdited: isEdited$6,
10753
- onChange
10754
- });
10755
- }
10756
- if (type === 'textfield' && isCustomValidation) {
10757
- entries.push({
10758
- id: 'pattern',
10759
- component: Pattern,
10760
- getValue,
10761
- field,
10762
- isEdited: isEdited,
10763
- onChange
10764
- });
10765
- }
10766
- if (type === 'number') {
10767
- entries.push({
10768
- id: 'min',
10769
- component: Min,
10770
- getValue,
10771
- field,
10772
- isEdited: isEdited$6,
10773
- onChange
10774
- }, {
10775
- id: 'max',
10776
- component: Max,
10777
- getValue,
10778
- field,
10779
- isEdited: isEdited$6,
10780
- onChange
10781
- });
10782
- }
10973
+ entries.push({
10974
+ id: 'validationType',
10975
+ component: ValidationType,
10976
+ getValue,
10977
+ field,
10978
+ editField,
10979
+ isEdited: isEdited,
10980
+ onChange,
10981
+ isDefaultVisible: field => field.type === 'textfield'
10982
+ });
10983
+ entries.push({
10984
+ id: 'minLength',
10985
+ component: MinLength,
10986
+ getValue,
10987
+ field,
10988
+ isEdited: isEdited$6,
10989
+ onChange,
10990
+ isDefaultVisible: field => INPUTS.includes(field.type) && (type === 'textarea' || type === 'textfield' && isCustomValidation)
10991
+ }, {
10992
+ id: 'maxLength',
10993
+ component: MaxLength,
10994
+ getValue,
10995
+ field,
10996
+ isEdited: isEdited$6,
10997
+ onChange,
10998
+ isDefaultVisible: field => INPUTS.includes(field.type) && (type === 'textarea' || type === 'textfield' && isCustomValidation)
10999
+ });
11000
+ entries.push({
11001
+ id: 'pattern',
11002
+ component: Pattern,
11003
+ getValue,
11004
+ field,
11005
+ isEdited: isEdited,
11006
+ onChange,
11007
+ isDefaultVisible: field => INPUTS.includes(field.type) && type === 'textfield' && isCustomValidation
11008
+ });
11009
+ entries.push({
11010
+ id: 'min',
11011
+ component: Min,
11012
+ getValue,
11013
+ field,
11014
+ isEdited: isEdited$6,
11015
+ onChange,
11016
+ isDefaultVisible: field => field.type === 'number'
11017
+ }, {
11018
+ id: 'max',
11019
+ component: Max,
11020
+ getValue,
11021
+ field,
11022
+ isEdited: isEdited$6,
11023
+ onChange,
11024
+ isDefaultVisible: field => field.type === 'number'
11025
+ });
10783
11026
  return {
10784
11027
  id: 'validation',
10785
11028
  label: 'Validation',
@@ -10933,12 +11176,14 @@ function ValidationType(props) {
10933
11176
  });
10934
11177
  }
10935
11178
 
10936
- function ValuesGroups(field, editField) {
11179
+ function ValuesGroups(field, editField, getService) {
10937
11180
  const {
10938
11181
  type,
10939
11182
  id: fieldId
10940
11183
  } = field;
10941
- if (!VALUES_INPUTS.includes(type)) {
11184
+ const formFields = getService('formFields');
11185
+ const fieldDefinition = formFields.get(type).config;
11186
+ if (!VALUES_INPUTS.includes(type) && !hasValuesGroupsConfigured(fieldDefinition)) {
10942
11187
  return [];
10943
11188
  }
10944
11189
  const context = {
@@ -10947,8 +11192,8 @@ function ValuesGroups(field, editField) {
10947
11192
  };
10948
11193
  const valuesSourceId = `${fieldId}-valuesSource`;
10949
11194
 
10950
- /**
10951
- * @type {Array<Group|ListGroup>}
11195
+ /**
11196
+ * @type {Array<Group|ListGroup>}
10952
11197
  */
10953
11198
  const groups = [{
10954
11199
  id: valuesSourceId,
@@ -11069,13 +11314,13 @@ function CustomPropertiesGroup(field, editField) {
11069
11314
 
11070
11315
  // helpers //////////
11071
11316
 
11072
- /**
11073
- * Returns copy of object without key.
11074
- *
11075
- * @param {Object} properties
11076
- * @param {string} oldKey
11077
- *
11078
- * @returns {Object}
11317
+ /**
11318
+ * Returns copy of object without key.
11319
+ *
11320
+ * @param {Object} properties
11321
+ * @param {string} oldKey
11322
+ *
11323
+ * @returns {Object}
11079
11324
  */
11080
11325
  function removeKey(properties, oldKey) {
11081
11326
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -11144,158 +11389,64 @@ function ConditionGroup(field, editField) {
11144
11389
  };
11145
11390
  }
11146
11391
 
11147
- function getGroups(field, editField, getService) {
11148
- if (!field) {
11149
- return [];
11150
- }
11151
- 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)];
11152
-
11153
- // contract: if a group returns null, it should not be displayed at all
11154
- return groups.filter(group => group !== null);
11155
- }
11156
- function FormPropertiesPanel(props) {
11157
- const {
11158
- eventBus,
11159
- injector
11160
- } = props;
11161
- const formEditor = injector.get('formEditor');
11162
- const modeling = injector.get('modeling');
11163
- const selectionModule = injector.get('selection');
11164
- const propertiesPanelConfig = injector.get('config.propertiesPanel') || {};
11165
- const {
11166
- feelPopupContainer
11167
- } = propertiesPanelConfig;
11168
- const [state, setState] = hooks.useState({
11169
- selectedFormField: selectionModule.get() || formEditor._getState().schema
11170
- });
11171
- const selectedFormField = state.selectedFormField;
11172
- const refresh = hooks.useCallback(field => {
11173
- // TODO(skaiir): rework state management, re-rendering the whole properties panel is not the way to go
11174
- // https://github.com/bpmn-io/form-js/issues/686
11175
- setState({
11176
- selectedFormField: selectionModule.get() || formEditor._getState().schema
11177
- });
11178
-
11179
- // notify interested parties on property panel updates
11180
- eventBus.fire('propertiesPanel.updated', {
11181
- formField: field
11182
- });
11183
- }, [eventBus, formEditor, selectionModule]);
11184
- hooks.useLayoutEffect(() => {
11185
- /**
11186
- * TODO(pinussilvestrus): update with actual updated element,
11187
- * once we have a proper updater/change support
11188
- */
11189
- eventBus.on('changed', refresh);
11190
- eventBus.on('import.done', refresh);
11191
- eventBus.on('selection.changed', refresh);
11192
- return () => {
11193
- eventBus.off('changed', refresh);
11194
- eventBus.off('import.done', refresh);
11195
- eventBus.off('selection.changed', refresh);
11196
- };
11197
- }, [eventBus, refresh]);
11198
- const getService = (type, strict = true) => injector.get(type, strict);
11199
- const propertiesPanelContext = {
11200
- getService
11201
- };
11202
- const onFocus = () => eventBus.fire('propertiesPanel.focusin');
11203
- const onBlur = () => eventBus.fire('propertiesPanel.focusout');
11204
- const editField = hooks.useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]);
11205
- return jsxRuntime.jsx("div", {
11206
- class: "fjs-properties-panel",
11207
- "data-field": selectedFormField && selectedFormField.id,
11208
- onFocusCapture: onFocus,
11209
- onBlurCapture: onBlur,
11210
- children: jsxRuntime.jsx(FormPropertiesPanelContext.Provider, {
11211
- value: propertiesPanelContext,
11212
- children: jsxRuntime.jsx(PropertiesPanel, {
11213
- element: selectedFormField,
11214
- eventBus: eventBus,
11215
- groups: getGroups(selectedFormField, editField, getService),
11216
- headerProvider: PropertiesPanelHeaderProvider,
11217
- placeholderProvider: PropertiesPanelPlaceholderProvider,
11218
- feelPopupContainer: feelPopupContainer
11219
- })
11220
- })
11221
- });
11222
- }
11223
-
11224
- class PropertiesPanelRenderer {
11225
- constructor(propertiesPanelConfig, injector, eventBus) {
11226
- const {
11227
- parent
11228
- } = propertiesPanelConfig || {};
11229
- this._eventBus = eventBus;
11392
+ class PropertiesProvider {
11393
+ constructor(propertiesPanel, injector) {
11230
11394
  this._injector = injector;
11231
- this._container = minDom.domify('<div class="fjs-properties-container" input-handle-modified-keys="y,z"></div>');
11232
- if (parent) {
11233
- this.attachTo(parent);
11234
- }
11235
- this._eventBus.once('formEditor.rendered', 500, () => {
11236
- this._render();
11237
- });
11395
+ propertiesPanel.registerProvider(this);
11238
11396
  }
11239
-
11240
- /**
11241
- * Attach the properties panel to a parent node.
11242
- *
11243
- * @param {HTMLElement} container
11244
- */
11245
- attachTo(container) {
11246
- if (!container) {
11247
- throw new Error('container required');
11248
- }
11249
- if (typeof container === 'string') {
11250
- container = minDom.query(container);
11251
- }
11252
-
11253
- // (1) detach from old parent
11254
- this.detach();
11255
-
11256
- // (2) append to parent container
11257
- container.appendChild(this._container);
11258
-
11259
- // (3) notify interested parties
11260
- this._eventBus.fire('propertiesPanel.attach');
11397
+ _filterVisibleEntries(groups, field, getService) {
11398
+ return groups.forEach(group => {
11399
+ const {
11400
+ entries
11401
+ } = group;
11402
+ const {
11403
+ type
11404
+ } = field;
11405
+ const formFields = getService('formFields');
11406
+ const fieldDefinition = formFields.get(type).config;
11407
+ if (!entries) {
11408
+ return;
11409
+ }
11410
+ group.entries = entries.filter(entry => {
11411
+ const {
11412
+ isDefaultVisible
11413
+ } = entry;
11414
+ if (!isDefaultVisible) {
11415
+ return true;
11416
+ }
11417
+ return isDefaultVisible(field) || hasEntryConfigured(fieldDefinition, entry.id);
11418
+ });
11419
+ });
11261
11420
  }
11421
+ getGroups(field, editField) {
11422
+ return groups => {
11423
+ if (!field) {
11424
+ return groups;
11425
+ }
11426
+ const getService = (type, strict = true) => this._injector.get(type, strict);
11427
+ 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);
11428
+ this._filterVisibleEntries(groups, field, getService);
11262
11429
 
11263
- /**
11264
- * Detach the properties panel from its parent node.
11265
- */
11266
- detach() {
11267
- const parentNode = this._container.parentNode;
11268
- if (parentNode) {
11269
- parentNode.removeChild(this._container);
11270
- this._eventBus.fire('propertiesPanel.detach');
11271
- }
11272
- }
11273
- _render() {
11274
- preact.render(jsxRuntime.jsx(FormPropertiesPanel, {
11275
- eventBus: this._eventBus,
11276
- injector: this._injector
11277
- }), this._container);
11278
- this._eventBus.fire('propertiesPanel.rendered');
11279
- }
11280
- _destroy() {
11281
- if (this._container) {
11282
- preact.render(null, this._container);
11283
- this._eventBus.fire('propertiesPanel.destroyed');
11284
- }
11430
+ // contract: if a group has no entries or items, it should not be displayed at all
11431
+ return groups.filter(group => {
11432
+ return group.items || group.entries && group.entries.length;
11433
+ });
11434
+ };
11285
11435
  }
11286
11436
  }
11287
- PropertiesPanelRenderer.$inject = ['config.propertiesPanel', 'injector', 'eventBus'];
11437
+ PropertiesProvider.$inject = ['propertiesPanel', 'injector'];
11288
11438
 
11289
11439
  var PropertiesPanelModule = {
11290
11440
  __depends__: [index],
11291
- __init__: ['propertiesPanel'],
11292
- propertiesPanel: ['type', PropertiesPanelRenderer]
11441
+ __init__: ['propertiesPanel', 'propertiesProvider'],
11442
+ propertiesPanel: ['type', PropertiesPanelRenderer],
11443
+ propertiesProvider: ['type', PropertiesProvider]
11293
11444
  };
11294
11445
 
11295
- /**
11296
- * Manages the rendering of visual plugins.
11297
- * @constructor
11298
- * @param {Object} eventBus - Event bus for the application.
11446
+ /**
11447
+ * Manages the rendering of visual plugins.
11448
+ * @constructor
11449
+ * @param {Object} eventBus - Event bus for the application.
11299
11450
  */
11300
11451
  class RenderInjector extends SectionModuleBase {
11301
11452
  constructor(eventBus) {
@@ -11304,10 +11455,10 @@ class RenderInjector extends SectionModuleBase {
11304
11455
  this.registeredRenderers = [];
11305
11456
  }
11306
11457
 
11307
- /**
11308
- * Inject a new renderer into the injector.
11309
- * @param {string} identifier - Identifier for the renderer.
11310
- * @param {Function} Renderer - The renderer function.
11458
+ /**
11459
+ * Inject a new renderer into the injector.
11460
+ * @param {string} identifier - Identifier for the renderer.
11461
+ * @param {Function} Renderer - The renderer function.
11311
11462
  */
11312
11463
  attachRenderer(identifier, Renderer) {
11313
11464
  this.registeredRenderers = [...this.registeredRenderers, {
@@ -11316,17 +11467,17 @@ class RenderInjector extends SectionModuleBase {
11316
11467
  }];
11317
11468
  }
11318
11469
 
11319
- /**
11320
- * Detach a renderer from the by key injector.
11321
- * @param {string} identifier - Identifier for the renderer.
11470
+ /**
11471
+ * Detach a renderer from the by key injector.
11472
+ * @param {string} identifier - Identifier for the renderer.
11322
11473
  */
11323
11474
  detachRenderer(identifier) {
11324
11475
  this.registeredRenderers = this.registeredRenderers.filter(r => r.identifier !== identifier);
11325
11476
  }
11326
11477
 
11327
- /**
11328
- * Returns the registered renderers.
11329
- * @returns {Array} Array of registered renderers.
11478
+ /**
11479
+ * Returns the registered renderers.
11480
+ * @returns {Array} Array of registered renderers.
11330
11481
  */
11331
11482
  fetchRenderers() {
11332
11483
  return this.registeredRenderers;
@@ -11360,48 +11511,48 @@ var ExpressionLanguageModule = {
11360
11511
 
11361
11512
  const ids = new Ids([32, 36, 1]);
11362
11513
 
11363
- /**
11364
- * @typedef { import('./types').Injector } Injector
11365
- * @typedef { import('./types').Module } Module
11366
- * @typedef { import('./types').Schema } Schema
11367
- *
11368
- * @typedef { import('./types').FormEditorOptions } FormEditorOptions
11369
- * @typedef { import('./types').FormEditorProperties } FormEditorProperties
11370
- *
11371
- * @typedef { {
11372
- * properties: FormEditorProperties,
11373
- * schema: Schema
11374
- * } } State
11375
- *
11376
- * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
11377
- * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
11378
- * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
11514
+ /**
11515
+ * @typedef { import('./types').Injector } Injector
11516
+ * @typedef { import('./types').Module } Module
11517
+ * @typedef { import('./types').Schema } Schema
11518
+ *
11519
+ * @typedef { import('./types').FormEditorOptions } FormEditorOptions
11520
+ * @typedef { import('./types').FormEditorProperties } FormEditorProperties
11521
+ *
11522
+ * @typedef { {
11523
+ * properties: FormEditorProperties,
11524
+ * schema: Schema
11525
+ * } } State
11526
+ *
11527
+ * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
11528
+ * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
11529
+ * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
11379
11530
  */
11380
11531
 
11381
- /**
11382
- * The form editor.
11532
+ /**
11533
+ * The form editor.
11383
11534
  */
11384
11535
  class FormEditor {
11385
- /**
11386
- * @constructor
11387
- * @param {FormEditorOptions} options
11536
+ /**
11537
+ * @constructor
11538
+ * @param {FormEditorOptions} options
11388
11539
  */
11389
11540
  constructor(options = {}) {
11390
- /**
11391
- * @public
11392
- * @type {OnEventType}
11541
+ /**
11542
+ * @public
11543
+ * @type {OnEventType}
11393
11544
  */
11394
11545
  this.on = this._onEvent;
11395
11546
 
11396
- /**
11397
- * @public
11398
- * @type {String}
11547
+ /**
11548
+ * @public
11549
+ * @type {String}
11399
11550
  */
11400
11551
  this._id = ids.next();
11401
11552
 
11402
- /**
11403
- * @private
11404
- * @type {Element}
11553
+ /**
11554
+ * @private
11555
+ * @type {Element}
11405
11556
  */
11406
11557
  this._container = formJsViewer.createFormContainer();
11407
11558
  this._container.setAttribute('input-handle-modified-keys', 'z,y');
@@ -11412,15 +11563,15 @@ class FormEditor {
11412
11563
  properties = {}
11413
11564
  } = options;
11414
11565
 
11415
- /**
11416
- * @private
11417
- * @type {any}
11566
+ /**
11567
+ * @private
11568
+ * @type {any}
11418
11569
  */
11419
11570
  this.exporter = exporter;
11420
11571
 
11421
- /**
11422
- * @private
11423
- * @type {State}
11572
+ /**
11573
+ * @private
11574
+ * @type {State}
11424
11575
  */
11425
11576
  this._state = {
11426
11577
  properties,
@@ -11449,10 +11600,10 @@ class FormEditor {
11449
11600
  this._detach(false);
11450
11601
  }
11451
11602
 
11452
- /**
11453
- * @param {Schema} schema
11454
- *
11455
- * @return {Promise<{ warnings: Array<any> }>}
11603
+ /**
11604
+ * @param {Schema} schema
11605
+ *
11606
+ * @return {Promise<{ warnings: Array<any> }>}
11456
11607
  */
11457
11608
  importSchema(schema) {
11458
11609
  return new Promise((resolve, reject) => {
@@ -11481,15 +11632,15 @@ class FormEditor {
11481
11632
  });
11482
11633
  }
11483
11634
 
11484
- /**
11485
- * @returns {Schema}
11635
+ /**
11636
+ * @returns {Schema}
11486
11637
  */
11487
11638
  saveSchema() {
11488
11639
  return this.getSchema();
11489
11640
  }
11490
11641
 
11491
- /**
11492
- * @returns {Schema}
11642
+ /**
11643
+ * @returns {Schema}
11493
11644
  */
11494
11645
  getSchema() {
11495
11646
  const {
@@ -11498,8 +11649,8 @@ class FormEditor {
11498
11649
  return exportSchema(schema, this.exporter, formJsViewer.schemaVersion);
11499
11650
  }
11500
11651
 
11501
- /**
11502
- * @param {Element|string} parentNode
11652
+ /**
11653
+ * @param {Element|string} parentNode
11503
11654
  */
11504
11655
  attachTo(parentNode) {
11505
11656
  if (!parentNode) {
@@ -11517,10 +11668,10 @@ class FormEditor {
11517
11668
  this._detach();
11518
11669
  }
11519
11670
 
11520
- /**
11521
- * @internal
11522
- *
11523
- * @param {boolean} [emit]
11671
+ /**
11672
+ * @internal
11673
+ *
11674
+ * @param {boolean} [emit]
11524
11675
  */
11525
11676
  _detach(emit = true) {
11526
11677
  const container = this._container,
@@ -11534,9 +11685,9 @@ class FormEditor {
11534
11685
  parentNode.removeChild(container);
11535
11686
  }
11536
11687
 
11537
- /**
11538
- * @param {any} property
11539
- * @param {any} value
11688
+ /**
11689
+ * @param {any} property
11690
+ * @param {any} value
11540
11691
  */
11541
11692
  setProperty(property, value) {
11542
11693
  const properties = minDash.set(this._getState().properties, [property], value);
@@ -11545,21 +11696,21 @@ class FormEditor {
11545
11696
  });
11546
11697
  }
11547
11698
 
11548
- /**
11549
- * @param {string} type
11550
- * @param {Function} handler
11699
+ /**
11700
+ * @param {string} type
11701
+ * @param {Function} handler
11551
11702
  */
11552
11703
  off(type, handler) {
11553
11704
  this.get('eventBus').off(type, handler);
11554
11705
  }
11555
11706
 
11556
- /**
11557
- * @internal
11558
- *
11559
- * @param {FormEditorOptions} options
11560
- * @param {Element} container
11561
- *
11562
- * @returns {Injector}
11707
+ /**
11708
+ * @internal
11709
+ *
11710
+ * @param {FormEditorOptions} options
11711
+ * @param {Element} container
11712
+ *
11713
+ * @returns {Injector}
11563
11714
  */
11564
11715
  _createInjector(options, container) {
11565
11716
  const {
@@ -11581,22 +11732,22 @@ class FormEditor {
11581
11732
  }, core, ...modules, ...additionalModules]);
11582
11733
  }
11583
11734
 
11584
- /**
11585
- * @internal
11735
+ /**
11736
+ * @internal
11586
11737
  */
11587
11738
  _emit(type, data) {
11588
11739
  this.get('eventBus').fire(type, data);
11589
11740
  }
11590
11741
 
11591
- /**
11592
- * @internal
11742
+ /**
11743
+ * @internal
11593
11744
  */
11594
11745
  _getState() {
11595
11746
  return this._state;
11596
11747
  }
11597
11748
 
11598
- /**
11599
- * @internal
11749
+ /**
11750
+ * @internal
11600
11751
  */
11601
11752
  _setState(state) {
11602
11753
  this._state = {
@@ -11606,15 +11757,15 @@ class FormEditor {
11606
11757
  this._emit('changed', this._getState());
11607
11758
  }
11608
11759
 
11609
- /**
11610
- * @internal
11760
+ /**
11761
+ * @internal
11611
11762
  */
11612
11763
  _getModules() {
11613
11764
  return [ModelingModule, EditorActionsModule, DraggingModule, KeyboardModule, SelectionModule, PaletteModule, ExpressionLanguageModule, formJsViewer.MarkdownModule, PropertiesPanelModule, RenderInjectionModule];
11614
11765
  }
11615
11766
 
11616
- /**
11617
- * @internal
11767
+ /**
11768
+ * @internal
11618
11769
  */
11619
11770
  _onEvent(type, priority, handler) {
11620
11771
  this.get('eventBus').on(type, priority, handler);
@@ -11668,4 +11819,9 @@ Object.defineProperty(exports, 'schemaVersion', {
11668
11819
  });
11669
11820
  exports.FormEditor = FormEditor;
11670
11821
  exports.createFormEditor = createFormEditor;
11822
+ exports.useDebounce = useDebounce;
11823
+ exports.usePrevious = usePrevious$1;
11824
+ exports.usePropertiesPanelService = useService;
11825
+ exports.useService = useService$1;
11826
+ exports.useVariables = useVariables;
11671
11827
  //# sourceMappingURL=index.cjs.map