@bpmn-io/form-js-editor 1.8.7 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import Ids from 'ids';
2
2
  import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Label as Label$3, IFrame, Text as Text$1, Html, Table, ExpressionField, FormFields, sanitizeImageSource, getAncestryList, FormContext, FormRenderContext, FormComponent, getScrollContainer, Importer, PathRegistry, FormLayouter, FieldFactory, FeelExpressionLanguage, OPTIONS_SOURCES, OPTIONS_SOURCES_PATHS, clone, runRecursively, 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, getOptionsSource, OPTIONS_SOURCES_DEFAULTS, OPTIONS_SOURCES_LABELS, SECURITY_ATTRIBUTES_DEFINITIONS, createFormContainer, createInjector, MarkdownRendererModule, schemaVersion } from '@bpmn-io/form-js-viewer';
3
3
  export { schemaVersion } from '@bpmn-io/form-js-viewer';
4
- import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, isString, uniqueBy, isObject, get, isDefined, sortBy, find, set as set$1, reduce, without, isNil, has } from 'min-dash';
4
+ import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, isString, uniqueBy, isObject, get, isDefined, set as set$1, reduce, without, isNil, has } from 'min-dash';
5
5
  import classnames from 'classnames';
6
6
  import { jsxs, jsx, Fragment as Fragment$1 } from 'preact/jsx-runtime';
7
7
  import { useContext, useRef, useEffect, useMemo, useState, useCallback, useLayoutEffect } from 'preact/hooks';
@@ -5373,6 +5373,21 @@ PopupIcon.defaultProps = {
5373
5373
  height: "16",
5374
5374
  viewBox: "0 0 32 32"
5375
5375
  };
5376
+ var CloseIcon = function CloseIcon(props) {
5377
+ return jsx("svg", {
5378
+ ...props,
5379
+ children: jsx("path", {
5380
+ fillRule: "evenodd",
5381
+ d: "m12 4.7-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7Z",
5382
+ fill: "currentColor"
5383
+ })
5384
+ });
5385
+ };
5386
+ CloseIcon.defaultProps = {
5387
+ xmlns: "http://www.w3.org/2000/svg",
5388
+ width: "16",
5389
+ height: "16"
5390
+ };
5376
5391
  function Header(props) {
5377
5392
  const {
5378
5393
  element,
@@ -6073,7 +6088,8 @@ const CodeEditor$1 = forwardRef((props, ref) => {
6073
6088
  tooltipContainer,
6074
6089
  enableGutters,
6075
6090
  hostLanguage,
6076
- singleLine
6091
+ singleLine,
6092
+ lineWrap: true
6077
6093
  });
6078
6094
  setEditor(editor);
6079
6095
  return () => {
@@ -6110,7 +6126,7 @@ const CodeEditor$1 = forwardRef((props, ref) => {
6110
6126
  title: "Open pop-up editor",
6111
6127
  class: "bio-properties-panel-open-feel-popup",
6112
6128
  onClick: () => onPopupOpen('feelers'),
6113
- children: jsx(ExternalLinkIcon, {})
6129
+ children: jsx(PopupIcon, {})
6114
6130
  })]
6115
6131
  });
6116
6132
  });
@@ -6150,6 +6166,7 @@ const CodeEditor = forwardRef((props, ref) => {
6150
6166
  onFeelToggle = noop$5,
6151
6167
  onLint = noop$5,
6152
6168
  onPopupOpen = noop$5,
6169
+ placeholder,
6153
6170
  popupOpen,
6154
6171
  disabled,
6155
6172
  tooltipContainer,
@@ -6186,6 +6203,7 @@ const CodeEditor = forwardRef((props, ref) => {
6186
6203
  onChange: handleInput,
6187
6204
  onKeyDown: onKeyDown,
6188
6205
  onLint: onLint,
6206
+ placeholder: placeholder,
6189
6207
  tooltipContainer: tooltipContainer,
6190
6208
  value: localValue,
6191
6209
  variables: variables,
@@ -6215,6 +6233,12 @@ const CodeEditor = forwardRef((props, ref) => {
6215
6233
  }
6216
6234
  editor.setVariables(variables);
6217
6235
  }, [variables]);
6236
+ useEffect(() => {
6237
+ if (!editor) {
6238
+ return;
6239
+ }
6240
+ editor.setPlaceholder(placeholder);
6241
+ }, [placeholder]);
6218
6242
  const handleClick = () => {
6219
6243
  ref.current.focus();
6220
6244
  };
@@ -6467,6 +6491,9 @@ function Title(props) {
6467
6491
  draggable,
6468
6492
  emit = () => {},
6469
6493
  title,
6494
+ showCloseButton = false,
6495
+ closeButtonTooltip = 'Close popup',
6496
+ onClose,
6470
6497
  ...rest
6471
6498
  } = props;
6472
6499
 
@@ -6537,7 +6564,12 @@ function Title(props) {
6537
6564
  }), jsx("div", {
6538
6565
  class: "bio-properties-panel-popup__title",
6539
6566
  children: title
6540
- }), children]
6567
+ }), children, showCloseButton && jsx("button", {
6568
+ title: closeButtonTooltip,
6569
+ class: "bio-properties-panel-popup__close",
6570
+ onClick: onClose,
6571
+ children: jsx(CloseIcon, {})
6572
+ })]
6541
6573
  });
6542
6574
  }
6543
6575
  function Body(props) {
@@ -6755,6 +6787,9 @@ function FeelPopupComponent(props) {
6755
6787
  children: [jsxs(Popup.Title, {
6756
6788
  title: title,
6757
6789
  emit: emit,
6790
+ showCloseButton: true,
6791
+ closeButtonTooltip: "Save and close",
6792
+ onClose: onClose,
6758
6793
  draggable: true,
6759
6794
  children: [type === 'feel' && jsxs("a", {
6760
6795
  href: "https://docs.camunda.io/docs/components/modeler/feel/what-is-feel/",
@@ -6796,14 +6831,6 @@ function FeelPopupComponent(props) {
6796
6831
  tooltipContainer: tooltipContainer
6797
6832
  })]
6798
6833
  })
6799
- }), jsx(Popup.Footer, {
6800
- children: jsx("button", {
6801
- type: "button",
6802
- onClick: () => onClose(),
6803
- title: "Close pop-up editor",
6804
- class: "bio-properties-panel-feel-popup__close-btn",
6805
- children: "Close"
6806
- })
6807
6834
  })]
6808
6835
  });
6809
6836
  }
@@ -7113,6 +7140,7 @@ function FeelTextfieldComponent(props) {
7113
7140
  hostLanguage,
7114
7141
  onInput,
7115
7142
  onError,
7143
+ placeholder,
7116
7144
  feel,
7117
7145
  value = '',
7118
7146
  disabled = false,
@@ -7287,6 +7315,7 @@ function FeelTextfieldComponent(props) {
7287
7315
  },
7288
7316
  onLint: handleLint,
7289
7317
  onPopupOpen: handlePopupOpen,
7318
+ placeholder: placeholder,
7290
7319
  value: feelOnlyValue,
7291
7320
  variables: variables,
7292
7321
  ref: editorRef,
@@ -7315,7 +7344,8 @@ const OptionalFeelInput = forwardRef((props, ref) => {
7315
7344
  onInput,
7316
7345
  value,
7317
7346
  onFocus,
7318
- onBlur
7347
+ onBlur,
7348
+ placeholder
7319
7349
  } = props;
7320
7350
  const inputRef = useRef();
7321
7351
 
@@ -7348,6 +7378,7 @@ const OptionalFeelInput = forwardRef((props, ref) => {
7348
7378
  onInput: e => onInput(e.target.value),
7349
7379
  onFocus: onFocus,
7350
7380
  onBlur: onBlur,
7381
+ placeholder: placeholder,
7351
7382
  value: value || ''
7352
7383
  });
7353
7384
  });
@@ -7405,7 +7436,8 @@ forwardRef((props, ref) => {
7405
7436
  onInput,
7406
7437
  value,
7407
7438
  onFocus,
7408
- onBlur
7439
+ onBlur,
7440
+ placeholder
7409
7441
  } = props;
7410
7442
  const inputRef = useRef();
7411
7443
 
@@ -7433,6 +7465,7 @@ forwardRef((props, ref) => {
7433
7465
  onInput: e => onInput(e.target.value),
7434
7466
  onFocus: onFocus,
7435
7467
  onBlur: onBlur,
7468
+ placeholder: placeholder,
7436
7469
  value: value || '',
7437
7470
  "data-gramm": "false"
7438
7471
  });
@@ -7528,6 +7561,7 @@ forwardRef((props, ref) => {
7528
7561
  * @param {Function} props.variables
7529
7562
  * @param {Function} props.onFocus
7530
7563
  * @param {Function} props.onBlur
7564
+ * @param {string} [props.placeholder]
7531
7565
  * @param {string|import('preact').Component} props.tooltip
7532
7566
  */
7533
7567
  function FeelEntry(props) {
@@ -7550,6 +7584,7 @@ function FeelEntry(props) {
7550
7584
  variables,
7551
7585
  onFocus,
7552
7586
  onBlur,
7587
+ placeholder,
7553
7588
  tooltip
7554
7589
  } = props;
7555
7590
  const [validationError, setValidationError] = useState(null);
@@ -7593,6 +7628,7 @@ function FeelEntry(props) {
7593
7628
  onError: onError,
7594
7629
  onFocus: onFocus,
7595
7630
  onBlur: onBlur,
7631
+ placeholder: placeholder,
7596
7632
  example: example,
7597
7633
  hostLanguage: hostLanguage,
7598
7634
  singleLine: singleLine,
@@ -7780,7 +7816,6 @@ const DEFAULT_TOOLTIP = {};
7780
7816
  * id: String,
7781
7817
  * items: Array<ListItemDefinition>,
7782
7818
  * label: String,
7783
- * shouldSort?: Boolean,
7784
7819
  * shouldOpen?: Boolean
7785
7820
  * } } ListGroupDefinition
7786
7821
  *
@@ -8108,6 +8143,7 @@ function ListItem(props) {
8108
8143
  } else if (isFunction(focusableInput.focus)) {
8109
8144
  focusableInput.focus();
8110
8145
  }
8146
+ focusableInput.scrollIntoView();
8111
8147
  }
8112
8148
  }
8113
8149
  }, [autoOpen, autoFocusEntry]);
@@ -8131,97 +8167,61 @@ function ListGroup(props) {
8131
8167
  id,
8132
8168
  items,
8133
8169
  label,
8134
- shouldOpen = true,
8135
- shouldSort = true
8170
+ shouldOpen = true
8136
8171
  } = props;
8172
+ useEffect(() => {
8173
+ if (props.shouldSort != undefined) {
8174
+ console.warn('the property \'shouldSort\' is no longer supported');
8175
+ }
8176
+ }, [props.shouldSort]);
8137
8177
  const groupRef = useRef(null);
8138
8178
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
8139
8179
  const [sticky, setSticky] = useState(false);
8140
8180
  const onShow = useCallback(() => setOpen(true), [setOpen]);
8141
- const [ordering, setOrdering] = useState([]);
8142
- const [newItemAdded, setNewItemAdded] = useState(false);
8181
+ const [localItems, setLocalItems] = useState([]);
8182
+ const [newlyAddedItemIds, setNewlyAddedItemIds] = useState([]);
8143
8183
 
8144
8184
  // Flag to mark that add button was clicked in the last render cycle
8145
8185
  const [addTriggered, setAddTriggered] = useState(false);
8146
- const prevItems = usePrevious(items);
8147
8186
  const prevElement = usePrevious(element);
8148
8187
  const elementChanged = element !== prevElement;
8149
- const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen);
8150
-
8151
- // reset initial ordering when element changes (before first render)
8152
- if (elementChanged) {
8153
- setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
8154
- }
8155
-
8156
- // keep ordering in sync to items - and open changes
8157
-
8158
- // (0) set initial ordering from given items
8188
+ const shouldHandleEffects = !elementChanged && shouldOpen;
8189
+
8190
+ // (0) delay setting items
8191
+ //
8192
+ // We need to this to align the render cycles of items
8193
+ // with the detection of newly added items.
8194
+ // This is important, because the autoOpen property can
8195
+ // only set per list item on its very first render.
8159
8196
  useEffect(() => {
8160
- if (!prevItems || !shouldSort) {
8161
- setOrdering(createOrdering(items));
8162
- }
8163
- }, [items, element]);
8197
+ setLocalItems(items);
8198
+ }, [items]);
8164
8199
 
8165
- // (1) items were added
8200
+ // (1) handle auto opening when items were added
8166
8201
  useEffect(() => {
8167
8202
  // reset addTriggered flag
8168
8203
  setAddTriggered(false);
8169
- if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
8170
- let add = [];
8171
- items.forEach(item => {
8172
- if (!ordering.includes(item.id)) {
8173
- add.push(item.id);
8204
+ if (shouldHandleEffects && localItems) {
8205
+ if (addTriggered) {
8206
+ const previousItemIds = localItems.map(item => item.id);
8207
+ const currentItemsIds = items.map(item => item.id);
8208
+ const newItemIds = currentItemsIds.filter(itemId => !previousItemIds.includes(itemId));
8209
+
8210
+ // open if not open, configured and triggered by add button
8211
+ //
8212
+ // TODO(marstamm): remove once we refactor layout handling for listGroups.
8213
+ // Ideally, opening should be handled as part of the `add` callback and
8214
+ // not be a concern for the ListGroup component.
8215
+ if (!open && shouldOpen && newItemIds.length > 0) {
8216
+ toggleOpen();
8174
8217
  }
8175
- });
8176
- let newOrdering = ordering;
8177
-
8178
- // open if not open, configured and triggered by add button
8179
- //
8180
- // TODO(marstamm): remove once we refactor layout handling for listGroups.
8181
- // Ideally, opening should be handled as part of the `add` callback and
8182
- // not be a concern for the ListGroup component.
8183
- if (addTriggered && !open && shouldOpen) {
8184
- toggleOpen();
8185
- }
8186
-
8187
- // filter when not open and configured
8188
- if (!open && shouldSort) {
8189
- newOrdering = createOrdering(sortItems(items));
8190
- }
8191
-
8192
- // add new items on top or bottom depending on sorting behavior
8193
- newOrdering = newOrdering.filter(item => !add.includes(item));
8194
- if (shouldSort) {
8195
- newOrdering.unshift(...add);
8218
+ setNewlyAddedItemIds(newItemIds);
8196
8219
  } else {
8197
- newOrdering.push(...add);
8220
+ // ignore newly added items that do not result from a triggered add
8221
+ setNewlyAddedItemIds([]);
8198
8222
  }
8199
- setOrdering(newOrdering);
8200
- setNewItemAdded(addTriggered);
8201
- } else {
8202
- setNewItemAdded(false);
8203
- }
8204
- }, [items, open, shouldHandleEffects, addTriggered]);
8205
-
8206
- // (2) sort items on open if shouldSort is set
8207
- useEffect(() => {
8208
- if (shouldSort && open && !newItemAdded) {
8209
- setOrdering(createOrdering(sortItems(items)));
8210
- }
8211
- }, [open, shouldSort]);
8212
-
8213
- // (3) items were deleted
8214
- useEffect(() => {
8215
- if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
8216
- let keep = [];
8217
- ordering.forEach(o => {
8218
- if (getItem(items, o)) {
8219
- keep.push(o);
8220
- }
8221
- });
8222
- setOrdering(keep);
8223
8223
  }
8224
- }, [items, shouldHandleEffects]);
8224
+ }, [items, open, shouldHandleEffects, addTriggered, localItems]);
8225
8225
 
8226
8226
  // set css class when group is sticky to top
8227
8227
  useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
@@ -8293,8 +8293,7 @@ function ListGroup(props) {
8293
8293
  class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
8294
8294
  children: jsx(LayoutContext.Provider, {
8295
8295
  value: propertiesPanelContext,
8296
- children: ordering.map((o, index) => {
8297
- const item = getItem(items, o);
8296
+ children: localItems.map((item, index) => {
8298
8297
  if (!item) {
8299
8298
  return;
8300
8299
  }
@@ -8304,7 +8303,7 @@ function ListGroup(props) {
8304
8303
 
8305
8304
  // if item was added, open it
8306
8305
  // Existing items will not be affected as autoOpen is only applied on first render
8307
- const autoOpen = newItemAdded;
8306
+ const autoOpen = newlyAddedItemIds.includes(item.id);
8308
8307
  return createElement(ListItem, {
8309
8308
  ...item,
8310
8309
  autoOpen: autoOpen,
@@ -8317,21 +8316,6 @@ function ListGroup(props) {
8317
8316
  })]
8318
8317
  });
8319
8318
  }
8320
-
8321
- // helpers ////////////////////
8322
-
8323
- /**
8324
- * Sorts given items alphanumeric by label
8325
- */
8326
- function sortItems(items) {
8327
- return sortBy(items, i => i.label.toLowerCase());
8328
- }
8329
- function getItem(items, id) {
8330
- return find(items, i => i.id === id);
8331
- }
8332
- function createOrdering(items) {
8333
- return items.map(i => i.id);
8334
- }
8335
8319
  function Checkbox(props) {
8336
8320
  const {
8337
8321
  id,
@@ -8618,6 +8602,7 @@ function TextArea(props) {
8618
8602
  onFocus,
8619
8603
  onBlur,
8620
8604
  autoResize,
8605
+ placeholder,
8621
8606
  rows = autoResize ? 1 : 2,
8622
8607
  tooltip
8623
8608
  } = props;
@@ -8660,6 +8645,7 @@ function TextArea(props) {
8660
8645
  onInput: handleInput,
8661
8646
  onFocus: onFocus,
8662
8647
  onBlur: onBlur,
8648
+ placeholder: placeholder,
8663
8649
  rows: rows,
8664
8650
  value: localValue,
8665
8651
  disabled: disabled,
@@ -8699,6 +8685,7 @@ function TextAreaEntry(props) {
8699
8685
  validate,
8700
8686
  onFocus,
8701
8687
  onBlur,
8688
+ placeholder,
8702
8689
  autoResize,
8703
8690
  tooltip
8704
8691
  } = props;
@@ -8734,6 +8721,7 @@ function TextAreaEntry(props) {
8734
8721
  debounce: debounce,
8735
8722
  monospace: monospace,
8736
8723
  disabled: disabled,
8724
+ placeholder: placeholder,
8737
8725
  autoResize: autoResize,
8738
8726
  tooltip: tooltip,
8739
8727
  element: element
@@ -8765,6 +8753,7 @@ function Textfield(props) {
8765
8753
  onInput,
8766
8754
  onFocus,
8767
8755
  onBlur,
8756
+ placeholder,
8768
8757
  value = '',
8769
8758
  tooltip
8770
8759
  } = props;
@@ -8806,6 +8795,7 @@ function Textfield(props) {
8806
8795
  onInput: handleInput,
8807
8796
  onFocus: onFocus,
8808
8797
  onBlur: onBlur,
8798
+ placeholder: placeholder,
8809
8799
  value: localValue
8810
8800
  })]
8811
8801
  });
@@ -8839,6 +8829,7 @@ function TextfieldEntry(props) {
8839
8829
  validate,
8840
8830
  onFocus,
8841
8831
  onBlur,
8832
+ placeholder,
8842
8833
  tooltip
8843
8834
  } = props;
8844
8835
  const globalError = useError(id);
@@ -8870,6 +8861,7 @@ function TextfieldEntry(props) {
8870
8861
  onInput: onInput,
8871
8862
  onFocus: onFocus,
8872
8863
  onBlur: onBlur,
8864
+ placeholder: placeholder,
8873
8865
  value: value,
8874
8866
  tooltip: tooltip,
8875
8867
  element: element
@@ -9018,83 +9010,64 @@ function hasIntegerPathSegment(path) {
9018
9010
  return path.split('.').some(segment => /^\d+$/.test(segment));
9019
9011
  }
9020
9012
 
9021
- function useService(type, strict) {
9013
+ const headerlessTypes = ['spacer', 'separator', 'expression', 'html'];
9014
+ function getPropertiesPanelHeaderProvider(options = {}) {
9022
9015
  const {
9023
- getService
9024
- } = useContext(FormPropertiesPanelContext);
9025
- return getService(type, strict);
9026
- }
9027
-
9028
- /**
9029
- * Retrieve list of variables from the form schema.
9030
- *
9031
- * @returns { string[] } list of variables used in form schema
9032
- */
9033
- function useVariables() {
9034
- const form = useService('formEditor');
9035
- const schema = form.getSchema();
9036
- return getSchemaVariables(schema);
9016
+ getDocumentationRef,
9017
+ formFields
9018
+ } = options;
9019
+ return {
9020
+ getElementLabel: field => {
9021
+ const {
9022
+ type
9023
+ } = field;
9024
+ if (headerlessTypes.includes(type)) {
9025
+ return '';
9026
+ }
9027
+ if (type === 'text') {
9028
+ return textToLabel(field.text);
9029
+ }
9030
+ if (type === 'image') {
9031
+ return field.alt;
9032
+ }
9033
+ if (type === 'default') {
9034
+ return field.id;
9035
+ }
9036
+ return field.label;
9037
+ },
9038
+ getElementIcon: field => {
9039
+ const {
9040
+ type
9041
+ } = field;
9042
+ const fieldDefinition = formFields.get(type).config;
9043
+ const Icon = fieldDefinition.icon || iconsByType(type);
9044
+ if (Icon) {
9045
+ return () => jsx(Icon, {
9046
+ width: "36",
9047
+ height: "36",
9048
+ viewBox: "0 0 54 54"
9049
+ });
9050
+ } else if (fieldDefinition.iconUrl) {
9051
+ return getPaletteIcon({
9052
+ iconUrl: fieldDefinition.iconUrl,
9053
+ label: fieldDefinition.label
9054
+ });
9055
+ }
9056
+ },
9057
+ getTypeLabel: field => {
9058
+ const {
9059
+ type
9060
+ } = field;
9061
+ if (type === 'default') {
9062
+ return 'Form';
9063
+ }
9064
+ const fieldDefinition = formFields.get(type).config;
9065
+ return fieldDefinition.label || type;
9066
+ },
9067
+ getDocumentationRef
9068
+ };
9037
9069
  }
9038
9070
 
9039
- const headerlessTypes = ['spacer', 'separator', 'expression', 'html'];
9040
- const PropertiesPanelHeaderProvider = {
9041
- getElementLabel: field => {
9042
- const {
9043
- type
9044
- } = field;
9045
- if (headerlessTypes.includes(type)) {
9046
- return '';
9047
- }
9048
- if (type === 'text') {
9049
- return textToLabel(field.text);
9050
- }
9051
- if (type === 'image') {
9052
- return field.alt;
9053
- }
9054
- if (type === 'default') {
9055
- return field.id;
9056
- }
9057
- return field.label;
9058
- },
9059
- getElementIcon: field => {
9060
- const {
9061
- type
9062
- } = field;
9063
-
9064
- // @Note: We know that we are inside the properties panel context,
9065
- // so we can savely use the hook here.
9066
- // eslint-disable-next-line react-hooks/rules-of-hooks
9067
- const fieldDefinition = useService('formFields').get(type).config;
9068
- const Icon = fieldDefinition.icon || iconsByType(type);
9069
- if (Icon) {
9070
- return () => jsx(Icon, {
9071
- width: "36",
9072
- height: "36",
9073
- viewBox: "0 0 54 54"
9074
- });
9075
- } else if (fieldDefinition.iconUrl) {
9076
- return getPaletteIcon({
9077
- iconUrl: fieldDefinition.iconUrl,
9078
- label: fieldDefinition.label
9079
- });
9080
- }
9081
- },
9082
- getTypeLabel: field => {
9083
- const {
9084
- type
9085
- } = field;
9086
- if (type === 'default') {
9087
- return 'Form';
9088
- }
9089
-
9090
- // @Note: We know that we are inside the properties panel context,
9091
- // so we can savely use the hook here.
9092
- // eslint-disable-next-line react-hooks/rules-of-hooks
9093
- const fieldDefinition = useService('formFields').get(type).config;
9094
- return fieldDefinition.label || type;
9095
- }
9096
- };
9097
-
9098
9071
  /**
9099
9072
  * Provide placeholders for empty and multiple state.
9100
9073
  */
@@ -9111,6 +9084,7 @@ const PropertiesPanelPlaceholderProvider = {
9111
9084
  }
9112
9085
  };
9113
9086
 
9087
+ const EMPTY = {};
9114
9088
  function PropertiesPanel(props) {
9115
9089
  const {
9116
9090
  eventBus,
@@ -9120,7 +9094,7 @@ function PropertiesPanel(props) {
9120
9094
  const formEditor = injector.get('formEditor');
9121
9095
  const modeling = injector.get('modeling');
9122
9096
  const selectionModule = injector.get('selection');
9123
- const propertiesPanelConfig = injector.get('config.propertiesPanel') || {};
9097
+ const propertiesPanelConfig = injector.get('config.propertiesPanel') || EMPTY;
9124
9098
  const {
9125
9099
  feelPopupContainer
9126
9100
  } = propertiesPanelConfig;
@@ -9174,6 +9148,11 @@ function PropertiesPanel(props) {
9174
9148
  return updater(groups);
9175
9149
  }, []);
9176
9150
  }, [providers, selectedFormField, editField]);
9151
+ const formFields = getService('formFields');
9152
+ const PropertiesPanelHeaderProvider = useMemo(() => getPropertiesPanelHeaderProvider({
9153
+ getDocumentationRef: propertiesPanelConfig.getDocumentationRef,
9154
+ formFields
9155
+ }), [formFields, propertiesPanelConfig]);
9177
9156
  return jsx("div", {
9178
9157
  class: "fjs-properties-panel",
9179
9158
  "data-field": selectedFormField && selectedFormField.id,
@@ -9347,6 +9326,24 @@ function Action(props) {
9347
9326
  });
9348
9327
  }
9349
9328
 
9329
+ function useService(type, strict) {
9330
+ const {
9331
+ getService
9332
+ } = useContext(FormPropertiesPanelContext);
9333
+ return getService(type, strict);
9334
+ }
9335
+
9336
+ /**
9337
+ * Retrieve list of variables from the form schema.
9338
+ *
9339
+ * @returns { string[] } list of variables used in form schema
9340
+ */
9341
+ function useVariables() {
9342
+ const form = useService('formEditor');
9343
+ const schema = form.getSchema();
9344
+ return getSchemaVariables(schema);
9345
+ }
9346
+
9350
9347
  function AltTextEntry(props) {
9351
9348
  const {
9352
9349
  editField,
@@ -11633,8 +11630,7 @@ function StaticOptionsSourceEntry(props) {
11633
11630
  });
11634
11631
  return {
11635
11632
  items,
11636
- add: addEntry,
11637
- shouldSort: false
11633
+ add: addEntry
11638
11634
  };
11639
11635
  }
11640
11636
 
@@ -12478,8 +12474,7 @@ function StaticColumnsSourceEntry(props) {
12478
12474
  });
12479
12475
  return {
12480
12476
  items,
12481
- add: addEntry,
12482
- shouldSort: false
12477
+ add: addEntry
12483
12478
  };
12484
12479
  }
12485
12480
 
@@ -12981,8 +12976,7 @@ function CustomPropertiesGroup(field, editField) {
12981
12976
  id: 'custom-values',
12982
12977
  items,
12983
12978
  label: 'Custom properties',
12984
- tooltip: 'Add properties directly to the form schema, useful to configure functionality in custom-built task applications and form renderers.',
12985
- shouldSort: false
12979
+ tooltip: 'Add properties directly to the form schema, useful to configure functionality in custom-built task applications and form renderers.'
12986
12980
  };
12987
12981
  }
12988
12982