@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.cjs CHANGED
@@ -5393,6 +5393,21 @@ PopupIcon.defaultProps = {
5393
5393
  height: "16",
5394
5394
  viewBox: "0 0 32 32"
5395
5395
  };
5396
+ var CloseIcon = function CloseIcon(props) {
5397
+ return jsxRuntime.jsx("svg", {
5398
+ ...props,
5399
+ children: jsxRuntime.jsx("path", {
5400
+ fillRule: "evenodd",
5401
+ 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",
5402
+ fill: "currentColor"
5403
+ })
5404
+ });
5405
+ };
5406
+ CloseIcon.defaultProps = {
5407
+ xmlns: "http://www.w3.org/2000/svg",
5408
+ width: "16",
5409
+ height: "16"
5410
+ };
5396
5411
  function Header(props) {
5397
5412
  const {
5398
5413
  element,
@@ -6093,7 +6108,8 @@ const CodeEditor$1 = React.forwardRef((props, ref) => {
6093
6108
  tooltipContainer,
6094
6109
  enableGutters,
6095
6110
  hostLanguage,
6096
- singleLine
6111
+ singleLine,
6112
+ lineWrap: true
6097
6113
  });
6098
6114
  setEditor(editor);
6099
6115
  return () => {
@@ -6130,7 +6146,7 @@ const CodeEditor$1 = React.forwardRef((props, ref) => {
6130
6146
  title: "Open pop-up editor",
6131
6147
  class: "bio-properties-panel-open-feel-popup",
6132
6148
  onClick: () => onPopupOpen('feelers'),
6133
- children: jsxRuntime.jsx(ExternalLinkIcon, {})
6149
+ children: jsxRuntime.jsx(PopupIcon, {})
6134
6150
  })]
6135
6151
  });
6136
6152
  });
@@ -6170,6 +6186,7 @@ const CodeEditor = React.forwardRef((props, ref) => {
6170
6186
  onFeelToggle = noop$5,
6171
6187
  onLint = noop$5,
6172
6188
  onPopupOpen = noop$5,
6189
+ placeholder,
6173
6190
  popupOpen,
6174
6191
  disabled,
6175
6192
  tooltipContainer,
@@ -6206,6 +6223,7 @@ const CodeEditor = React.forwardRef((props, ref) => {
6206
6223
  onChange: handleInput,
6207
6224
  onKeyDown: onKeyDown,
6208
6225
  onLint: onLint,
6226
+ placeholder: placeholder,
6209
6227
  tooltipContainer: tooltipContainer,
6210
6228
  value: localValue,
6211
6229
  variables: variables,
@@ -6235,6 +6253,12 @@ const CodeEditor = React.forwardRef((props, ref) => {
6235
6253
  }
6236
6254
  editor.setVariables(variables);
6237
6255
  }, [variables]);
6256
+ hooks.useEffect(() => {
6257
+ if (!editor) {
6258
+ return;
6259
+ }
6260
+ editor.setPlaceholder(placeholder);
6261
+ }, [placeholder]);
6238
6262
  const handleClick = () => {
6239
6263
  ref.current.focus();
6240
6264
  };
@@ -6487,6 +6511,9 @@ function Title(props) {
6487
6511
  draggable,
6488
6512
  emit = () => {},
6489
6513
  title,
6514
+ showCloseButton = false,
6515
+ closeButtonTooltip = 'Close popup',
6516
+ onClose,
6490
6517
  ...rest
6491
6518
  } = props;
6492
6519
 
@@ -6557,7 +6584,12 @@ function Title(props) {
6557
6584
  }), jsxRuntime.jsx("div", {
6558
6585
  class: "bio-properties-panel-popup__title",
6559
6586
  children: title
6560
- }), children]
6587
+ }), children, showCloseButton && jsxRuntime.jsx("button", {
6588
+ title: closeButtonTooltip,
6589
+ class: "bio-properties-panel-popup__close",
6590
+ onClick: onClose,
6591
+ children: jsxRuntime.jsx(CloseIcon, {})
6592
+ })]
6561
6593
  });
6562
6594
  }
6563
6595
  function Body(props) {
@@ -6775,6 +6807,9 @@ function FeelPopupComponent(props) {
6775
6807
  children: [jsxRuntime.jsxs(Popup.Title, {
6776
6808
  title: title,
6777
6809
  emit: emit,
6810
+ showCloseButton: true,
6811
+ closeButtonTooltip: "Save and close",
6812
+ onClose: onClose,
6778
6813
  draggable: true,
6779
6814
  children: [type === 'feel' && jsxRuntime.jsxs("a", {
6780
6815
  href: "https://docs.camunda.io/docs/components/modeler/feel/what-is-feel/",
@@ -6816,14 +6851,6 @@ function FeelPopupComponent(props) {
6816
6851
  tooltipContainer: tooltipContainer
6817
6852
  })]
6818
6853
  })
6819
- }), jsxRuntime.jsx(Popup.Footer, {
6820
- children: jsxRuntime.jsx("button", {
6821
- type: "button",
6822
- onClick: () => onClose(),
6823
- title: "Close pop-up editor",
6824
- class: "bio-properties-panel-feel-popup__close-btn",
6825
- children: "Close"
6826
- })
6827
6854
  })]
6828
6855
  });
6829
6856
  }
@@ -7133,6 +7160,7 @@ function FeelTextfieldComponent(props) {
7133
7160
  hostLanguage,
7134
7161
  onInput,
7135
7162
  onError,
7163
+ placeholder,
7136
7164
  feel,
7137
7165
  value = '',
7138
7166
  disabled = false,
@@ -7307,6 +7335,7 @@ function FeelTextfieldComponent(props) {
7307
7335
  },
7308
7336
  onLint: handleLint,
7309
7337
  onPopupOpen: handlePopupOpen,
7338
+ placeholder: placeholder,
7310
7339
  value: feelOnlyValue,
7311
7340
  variables: variables,
7312
7341
  ref: editorRef,
@@ -7335,7 +7364,8 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
7335
7364
  onInput,
7336
7365
  value,
7337
7366
  onFocus,
7338
- onBlur
7367
+ onBlur,
7368
+ placeholder
7339
7369
  } = props;
7340
7370
  const inputRef = hooks.useRef();
7341
7371
 
@@ -7368,6 +7398,7 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
7368
7398
  onInput: e => onInput(e.target.value),
7369
7399
  onFocus: onFocus,
7370
7400
  onBlur: onBlur,
7401
+ placeholder: placeholder,
7371
7402
  value: value || ''
7372
7403
  });
7373
7404
  });
@@ -7425,7 +7456,8 @@ React.forwardRef((props, ref) => {
7425
7456
  onInput,
7426
7457
  value,
7427
7458
  onFocus,
7428
- onBlur
7459
+ onBlur,
7460
+ placeholder
7429
7461
  } = props;
7430
7462
  const inputRef = hooks.useRef();
7431
7463
 
@@ -7453,6 +7485,7 @@ React.forwardRef((props, ref) => {
7453
7485
  onInput: e => onInput(e.target.value),
7454
7486
  onFocus: onFocus,
7455
7487
  onBlur: onBlur,
7488
+ placeholder: placeholder,
7456
7489
  value: value || '',
7457
7490
  "data-gramm": "false"
7458
7491
  });
@@ -7548,6 +7581,7 @@ React.forwardRef((props, ref) => {
7548
7581
  * @param {Function} props.variables
7549
7582
  * @param {Function} props.onFocus
7550
7583
  * @param {Function} props.onBlur
7584
+ * @param {string} [props.placeholder]
7551
7585
  * @param {string|import('preact').Component} props.tooltip
7552
7586
  */
7553
7587
  function FeelEntry(props) {
@@ -7570,6 +7604,7 @@ function FeelEntry(props) {
7570
7604
  variables,
7571
7605
  onFocus,
7572
7606
  onBlur,
7607
+ placeholder,
7573
7608
  tooltip
7574
7609
  } = props;
7575
7610
  const [validationError, setValidationError] = hooks.useState(null);
@@ -7613,6 +7648,7 @@ function FeelEntry(props) {
7613
7648
  onError: onError,
7614
7649
  onFocus: onFocus,
7615
7650
  onBlur: onBlur,
7651
+ placeholder: placeholder,
7616
7652
  example: example,
7617
7653
  hostLanguage: hostLanguage,
7618
7654
  singleLine: singleLine,
@@ -7800,7 +7836,6 @@ const DEFAULT_TOOLTIP = {};
7800
7836
  * id: String,
7801
7837
  * items: Array<ListItemDefinition>,
7802
7838
  * label: String,
7803
- * shouldSort?: Boolean,
7804
7839
  * shouldOpen?: Boolean
7805
7840
  * } } ListGroupDefinition
7806
7841
  *
@@ -8128,6 +8163,7 @@ function ListItem(props) {
8128
8163
  } else if (minDash.isFunction(focusableInput.focus)) {
8129
8164
  focusableInput.focus();
8130
8165
  }
8166
+ focusableInput.scrollIntoView();
8131
8167
  }
8132
8168
  }
8133
8169
  }, [autoOpen, autoFocusEntry]);
@@ -8151,97 +8187,61 @@ function ListGroup(props) {
8151
8187
  id,
8152
8188
  items,
8153
8189
  label,
8154
- shouldOpen = true,
8155
- shouldSort = true
8190
+ shouldOpen = true
8156
8191
  } = props;
8192
+ hooks.useEffect(() => {
8193
+ if (props.shouldSort != undefined) {
8194
+ console.warn('the property \'shouldSort\' is no longer supported');
8195
+ }
8196
+ }, [props.shouldSort]);
8157
8197
  const groupRef = hooks.useRef(null);
8158
8198
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
8159
8199
  const [sticky, setSticky] = hooks.useState(false);
8160
8200
  const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
8161
- const [ordering, setOrdering] = hooks.useState([]);
8162
- const [newItemAdded, setNewItemAdded] = hooks.useState(false);
8201
+ const [localItems, setLocalItems] = hooks.useState([]);
8202
+ const [newlyAddedItemIds, setNewlyAddedItemIds] = hooks.useState([]);
8163
8203
 
8164
8204
  // Flag to mark that add button was clicked in the last render cycle
8165
8205
  const [addTriggered, setAddTriggered] = hooks.useState(false);
8166
- const prevItems = usePrevious(items);
8167
8206
  const prevElement = usePrevious(element);
8168
8207
  const elementChanged = element !== prevElement;
8169
- const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen);
8170
-
8171
- // reset initial ordering when element changes (before first render)
8172
- if (elementChanged) {
8173
- setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
8174
- }
8175
-
8176
- // keep ordering in sync to items - and open changes
8177
-
8178
- // (0) set initial ordering from given items
8208
+ const shouldHandleEffects = !elementChanged && shouldOpen;
8209
+
8210
+ // (0) delay setting items
8211
+ //
8212
+ // We need to this to align the render cycles of items
8213
+ // with the detection of newly added items.
8214
+ // This is important, because the autoOpen property can
8215
+ // only set per list item on its very first render.
8179
8216
  hooks.useEffect(() => {
8180
- if (!prevItems || !shouldSort) {
8181
- setOrdering(createOrdering(items));
8182
- }
8183
- }, [items, element]);
8217
+ setLocalItems(items);
8218
+ }, [items]);
8184
8219
 
8185
- // (1) items were added
8220
+ // (1) handle auto opening when items were added
8186
8221
  hooks.useEffect(() => {
8187
8222
  // reset addTriggered flag
8188
8223
  setAddTriggered(false);
8189
- if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
8190
- let add = [];
8191
- items.forEach(item => {
8192
- if (!ordering.includes(item.id)) {
8193
- add.push(item.id);
8224
+ if (shouldHandleEffects && localItems) {
8225
+ if (addTriggered) {
8226
+ const previousItemIds = localItems.map(item => item.id);
8227
+ const currentItemsIds = items.map(item => item.id);
8228
+ const newItemIds = currentItemsIds.filter(itemId => !previousItemIds.includes(itemId));
8229
+
8230
+ // open if not open, configured and triggered by add button
8231
+ //
8232
+ // TODO(marstamm): remove once we refactor layout handling for listGroups.
8233
+ // Ideally, opening should be handled as part of the `add` callback and
8234
+ // not be a concern for the ListGroup component.
8235
+ if (!open && shouldOpen && newItemIds.length > 0) {
8236
+ toggleOpen();
8194
8237
  }
8195
- });
8196
- let newOrdering = ordering;
8197
-
8198
- // open if not open, configured and triggered by add button
8199
- //
8200
- // TODO(marstamm): remove once we refactor layout handling for listGroups.
8201
- // Ideally, opening should be handled as part of the `add` callback and
8202
- // not be a concern for the ListGroup component.
8203
- if (addTriggered && !open && shouldOpen) {
8204
- toggleOpen();
8205
- }
8206
-
8207
- // filter when not open and configured
8208
- if (!open && shouldSort) {
8209
- newOrdering = createOrdering(sortItems(items));
8210
- }
8211
-
8212
- // add new items on top or bottom depending on sorting behavior
8213
- newOrdering = newOrdering.filter(item => !add.includes(item));
8214
- if (shouldSort) {
8215
- newOrdering.unshift(...add);
8238
+ setNewlyAddedItemIds(newItemIds);
8216
8239
  } else {
8217
- newOrdering.push(...add);
8240
+ // ignore newly added items that do not result from a triggered add
8241
+ setNewlyAddedItemIds([]);
8218
8242
  }
8219
- setOrdering(newOrdering);
8220
- setNewItemAdded(addTriggered);
8221
- } else {
8222
- setNewItemAdded(false);
8223
- }
8224
- }, [items, open, shouldHandleEffects, addTriggered]);
8225
-
8226
- // (2) sort items on open if shouldSort is set
8227
- hooks.useEffect(() => {
8228
- if (shouldSort && open && !newItemAdded) {
8229
- setOrdering(createOrdering(sortItems(items)));
8230
- }
8231
- }, [open, shouldSort]);
8232
-
8233
- // (3) items were deleted
8234
- hooks.useEffect(() => {
8235
- if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
8236
- let keep = [];
8237
- ordering.forEach(o => {
8238
- if (getItem(items, o)) {
8239
- keep.push(o);
8240
- }
8241
- });
8242
- setOrdering(keep);
8243
8243
  }
8244
- }, [items, shouldHandleEffects]);
8244
+ }, [items, open, shouldHandleEffects, addTriggered, localItems]);
8245
8245
 
8246
8246
  // set css class when group is sticky to top
8247
8247
  useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
@@ -8313,8 +8313,7 @@ function ListGroup(props) {
8313
8313
  class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
8314
8314
  children: jsxRuntime.jsx(LayoutContext.Provider, {
8315
8315
  value: propertiesPanelContext,
8316
- children: ordering.map((o, index) => {
8317
- const item = getItem(items, o);
8316
+ children: localItems.map((item, index) => {
8318
8317
  if (!item) {
8319
8318
  return;
8320
8319
  }
@@ -8324,7 +8323,7 @@ function ListGroup(props) {
8324
8323
 
8325
8324
  // if item was added, open it
8326
8325
  // Existing items will not be affected as autoOpen is only applied on first render
8327
- const autoOpen = newItemAdded;
8326
+ const autoOpen = newlyAddedItemIds.includes(item.id);
8328
8327
  return preact.createElement(ListItem, {
8329
8328
  ...item,
8330
8329
  autoOpen: autoOpen,
@@ -8337,21 +8336,6 @@ function ListGroup(props) {
8337
8336
  })]
8338
8337
  });
8339
8338
  }
8340
-
8341
- // helpers ////////////////////
8342
-
8343
- /**
8344
- * Sorts given items alphanumeric by label
8345
- */
8346
- function sortItems(items) {
8347
- return minDash.sortBy(items, i => i.label.toLowerCase());
8348
- }
8349
- function getItem(items, id) {
8350
- return minDash.find(items, i => i.id === id);
8351
- }
8352
- function createOrdering(items) {
8353
- return items.map(i => i.id);
8354
- }
8355
8339
  function Checkbox(props) {
8356
8340
  const {
8357
8341
  id,
@@ -8638,6 +8622,7 @@ function TextArea(props) {
8638
8622
  onFocus,
8639
8623
  onBlur,
8640
8624
  autoResize,
8625
+ placeholder,
8641
8626
  rows = autoResize ? 1 : 2,
8642
8627
  tooltip
8643
8628
  } = props;
@@ -8680,6 +8665,7 @@ function TextArea(props) {
8680
8665
  onInput: handleInput,
8681
8666
  onFocus: onFocus,
8682
8667
  onBlur: onBlur,
8668
+ placeholder: placeholder,
8683
8669
  rows: rows,
8684
8670
  value: localValue,
8685
8671
  disabled: disabled,
@@ -8719,6 +8705,7 @@ function TextAreaEntry(props) {
8719
8705
  validate,
8720
8706
  onFocus,
8721
8707
  onBlur,
8708
+ placeholder,
8722
8709
  autoResize,
8723
8710
  tooltip
8724
8711
  } = props;
@@ -8754,6 +8741,7 @@ function TextAreaEntry(props) {
8754
8741
  debounce: debounce,
8755
8742
  monospace: monospace,
8756
8743
  disabled: disabled,
8744
+ placeholder: placeholder,
8757
8745
  autoResize: autoResize,
8758
8746
  tooltip: tooltip,
8759
8747
  element: element
@@ -8785,6 +8773,7 @@ function Textfield(props) {
8785
8773
  onInput,
8786
8774
  onFocus,
8787
8775
  onBlur,
8776
+ placeholder,
8788
8777
  value = '',
8789
8778
  tooltip
8790
8779
  } = props;
@@ -8826,6 +8815,7 @@ function Textfield(props) {
8826
8815
  onInput: handleInput,
8827
8816
  onFocus: onFocus,
8828
8817
  onBlur: onBlur,
8818
+ placeholder: placeholder,
8829
8819
  value: localValue
8830
8820
  })]
8831
8821
  });
@@ -8859,6 +8849,7 @@ function TextfieldEntry(props) {
8859
8849
  validate,
8860
8850
  onFocus,
8861
8851
  onBlur,
8852
+ placeholder,
8862
8853
  tooltip
8863
8854
  } = props;
8864
8855
  const globalError = useError(id);
@@ -8890,6 +8881,7 @@ function TextfieldEntry(props) {
8890
8881
  onInput: onInput,
8891
8882
  onFocus: onFocus,
8892
8883
  onBlur: onBlur,
8884
+ placeholder: placeholder,
8893
8885
  value: value,
8894
8886
  tooltip: tooltip,
8895
8887
  element: element
@@ -9038,83 +9030,64 @@ function hasIntegerPathSegment(path) {
9038
9030
  return path.split('.').some(segment => /^\d+$/.test(segment));
9039
9031
  }
9040
9032
 
9041
- function useService(type, strict) {
9033
+ const headerlessTypes = ['spacer', 'separator', 'expression', 'html'];
9034
+ function getPropertiesPanelHeaderProvider(options = {}) {
9042
9035
  const {
9043
- getService
9044
- } = hooks.useContext(FormPropertiesPanelContext);
9045
- return getService(type, strict);
9046
- }
9047
-
9048
- /**
9049
- * Retrieve list of variables from the form schema.
9050
- *
9051
- * @returns { string[] } list of variables used in form schema
9052
- */
9053
- function useVariables() {
9054
- const form = useService('formEditor');
9055
- const schema = form.getSchema();
9056
- return formJsViewer.getSchemaVariables(schema);
9036
+ getDocumentationRef,
9037
+ formFields
9038
+ } = options;
9039
+ return {
9040
+ getElementLabel: field => {
9041
+ const {
9042
+ type
9043
+ } = field;
9044
+ if (headerlessTypes.includes(type)) {
9045
+ return '';
9046
+ }
9047
+ if (type === 'text') {
9048
+ return textToLabel(field.text);
9049
+ }
9050
+ if (type === 'image') {
9051
+ return field.alt;
9052
+ }
9053
+ if (type === 'default') {
9054
+ return field.id;
9055
+ }
9056
+ return field.label;
9057
+ },
9058
+ getElementIcon: field => {
9059
+ const {
9060
+ type
9061
+ } = field;
9062
+ const fieldDefinition = formFields.get(type).config;
9063
+ const Icon = fieldDefinition.icon || formJsViewer.iconsByType(type);
9064
+ if (Icon) {
9065
+ return () => jsxRuntime.jsx(Icon, {
9066
+ width: "36",
9067
+ height: "36",
9068
+ viewBox: "0 0 54 54"
9069
+ });
9070
+ } else if (fieldDefinition.iconUrl) {
9071
+ return getPaletteIcon({
9072
+ iconUrl: fieldDefinition.iconUrl,
9073
+ label: fieldDefinition.label
9074
+ });
9075
+ }
9076
+ },
9077
+ getTypeLabel: field => {
9078
+ const {
9079
+ type
9080
+ } = field;
9081
+ if (type === 'default') {
9082
+ return 'Form';
9083
+ }
9084
+ const fieldDefinition = formFields.get(type).config;
9085
+ return fieldDefinition.label || type;
9086
+ },
9087
+ getDocumentationRef
9088
+ };
9057
9089
  }
9058
9090
 
9059
- const headerlessTypes = ['spacer', 'separator', 'expression', 'html'];
9060
- const PropertiesPanelHeaderProvider = {
9061
- getElementLabel: field => {
9062
- const {
9063
- type
9064
- } = field;
9065
- if (headerlessTypes.includes(type)) {
9066
- return '';
9067
- }
9068
- if (type === 'text') {
9069
- return textToLabel(field.text);
9070
- }
9071
- if (type === 'image') {
9072
- return field.alt;
9073
- }
9074
- if (type === 'default') {
9075
- return field.id;
9076
- }
9077
- return field.label;
9078
- },
9079
- getElementIcon: field => {
9080
- const {
9081
- type
9082
- } = field;
9083
-
9084
- // @Note: We know that we are inside the properties panel context,
9085
- // so we can savely use the hook here.
9086
- // eslint-disable-next-line react-hooks/rules-of-hooks
9087
- const fieldDefinition = useService('formFields').get(type).config;
9088
- const Icon = fieldDefinition.icon || formJsViewer.iconsByType(type);
9089
- if (Icon) {
9090
- return () => jsxRuntime.jsx(Icon, {
9091
- width: "36",
9092
- height: "36",
9093
- viewBox: "0 0 54 54"
9094
- });
9095
- } else if (fieldDefinition.iconUrl) {
9096
- return getPaletteIcon({
9097
- iconUrl: fieldDefinition.iconUrl,
9098
- label: fieldDefinition.label
9099
- });
9100
- }
9101
- },
9102
- getTypeLabel: field => {
9103
- const {
9104
- type
9105
- } = field;
9106
- if (type === 'default') {
9107
- return 'Form';
9108
- }
9109
-
9110
- // @Note: We know that we are inside the properties panel context,
9111
- // so we can savely use the hook here.
9112
- // eslint-disable-next-line react-hooks/rules-of-hooks
9113
- const fieldDefinition = useService('formFields').get(type).config;
9114
- return fieldDefinition.label || type;
9115
- }
9116
- };
9117
-
9118
9091
  /**
9119
9092
  * Provide placeholders for empty and multiple state.
9120
9093
  */
@@ -9131,6 +9104,7 @@ const PropertiesPanelPlaceholderProvider = {
9131
9104
  }
9132
9105
  };
9133
9106
 
9107
+ const EMPTY = {};
9134
9108
  function PropertiesPanel(props) {
9135
9109
  const {
9136
9110
  eventBus,
@@ -9140,7 +9114,7 @@ function PropertiesPanel(props) {
9140
9114
  const formEditor = injector.get('formEditor');
9141
9115
  const modeling = injector.get('modeling');
9142
9116
  const selectionModule = injector.get('selection');
9143
- const propertiesPanelConfig = injector.get('config.propertiesPanel') || {};
9117
+ const propertiesPanelConfig = injector.get('config.propertiesPanel') || EMPTY;
9144
9118
  const {
9145
9119
  feelPopupContainer
9146
9120
  } = propertiesPanelConfig;
@@ -9194,6 +9168,11 @@ function PropertiesPanel(props) {
9194
9168
  return updater(groups);
9195
9169
  }, []);
9196
9170
  }, [providers, selectedFormField, editField]);
9171
+ const formFields = getService('formFields');
9172
+ const PropertiesPanelHeaderProvider = hooks.useMemo(() => getPropertiesPanelHeaderProvider({
9173
+ getDocumentationRef: propertiesPanelConfig.getDocumentationRef,
9174
+ formFields
9175
+ }), [formFields, propertiesPanelConfig]);
9197
9176
  return jsxRuntime.jsx("div", {
9198
9177
  class: "fjs-properties-panel",
9199
9178
  "data-field": selectedFormField && selectedFormField.id,
@@ -9367,6 +9346,24 @@ function Action(props) {
9367
9346
  });
9368
9347
  }
9369
9348
 
9349
+ function useService(type, strict) {
9350
+ const {
9351
+ getService
9352
+ } = hooks.useContext(FormPropertiesPanelContext);
9353
+ return getService(type, strict);
9354
+ }
9355
+
9356
+ /**
9357
+ * Retrieve list of variables from the form schema.
9358
+ *
9359
+ * @returns { string[] } list of variables used in form schema
9360
+ */
9361
+ function useVariables() {
9362
+ const form = useService('formEditor');
9363
+ const schema = form.getSchema();
9364
+ return formJsViewer.getSchemaVariables(schema);
9365
+ }
9366
+
9370
9367
  function AltTextEntry(props) {
9371
9368
  const {
9372
9369
  editField,
@@ -11653,8 +11650,7 @@ function StaticOptionsSourceEntry(props) {
11653
11650
  });
11654
11651
  return {
11655
11652
  items,
11656
- add: addEntry,
11657
- shouldSort: false
11653
+ add: addEntry
11658
11654
  };
11659
11655
  }
11660
11656
 
@@ -12498,8 +12494,7 @@ function StaticColumnsSourceEntry(props) {
12498
12494
  });
12499
12495
  return {
12500
12496
  items,
12501
- add: addEntry,
12502
- shouldSort: false
12497
+ add: addEntry
12503
12498
  };
12504
12499
  }
12505
12500
 
@@ -13001,8 +12996,7 @@ function CustomPropertiesGroup(field, editField) {
13001
12996
  id: 'custom-values',
13002
12997
  items,
13003
12998
  label: 'Custom properties',
13004
- tooltip: 'Add properties directly to the form schema, useful to configure functionality in custom-built task applications and form renderers.',
13005
- shouldSort: false
12999
+ tooltip: 'Add properties directly to the form schema, useful to configure functionality in custom-built task applications and form renderers.'
13006
13000
  };
13007
13001
  }
13008
13002