@bpmn-io/form-js-editor 1.4.0 → 1.5.0-alpha.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,4 +1,4 @@
1
- import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Text as Text$1, FormFields, sanitizeImageSource, FormContext, FormRenderContext, FormComponent, Importer, PathRegistry, FormLayouter, FieldFactory, runRecursively, clone, getSchemaVariables, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_PATHS, VALUES_SOURCES_LABELS, FeelExpressionLanguage, createFormContainer, createInjector, MarkdownModule, schemaVersion } from '@bpmn-io/form-js-viewer';
1
+ import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Text as Text$1, FormFields, sanitizeImageSource, FormContext, FormRenderContext, FormComponent, Importer, PathRegistry, FormLayouter, FieldFactory, runRecursively, clone, VALUES_SOURCES, VALUES_SOURCES_PATHS, getSchemaVariables, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_LABELS, FeelExpressionLanguage, createFormContainer, createInjector, MarkdownModule, schemaVersion } from '@bpmn-io/form-js-viewer';
2
2
  export { schemaVersion } from '@bpmn-io/form-js-viewer';
3
3
  import Ids from 'ids';
4
4
  import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, isString, set as set$1, reduce, isUndefined, without, has } from 'min-dash';
@@ -1970,6 +1970,7 @@ function Element$1(props) {
1970
1970
  const eventBus = useService$1('eventBus'),
1971
1971
  formEditor = useService$1('formEditor'),
1972
1972
  formFieldRegistry = useService$1('formFieldRegistry'),
1973
+ formFields = useService$1('formFields'),
1973
1974
  modeling = useService$1('modeling'),
1974
1975
  selection = useService$1('selection');
1975
1976
  const {
@@ -2055,6 +2056,7 @@ function Element$1(props) {
2055
2056
  field: field
2056
2057
  }), jsx(ContextPad, {
2057
2058
  children: selection.isSelected(field) && field.type !== 'default' ? jsx("button", {
2059
+ title: getRemoveButtonTitle(field, formFields),
2058
2060
  class: "fjs-context-pad-item",
2059
2061
  onClick: onRemove,
2060
2062
  children: jsx(DeleteIcon$1, {})
@@ -2375,6 +2377,13 @@ function findPaletteEntry(type, formFields) {
2375
2377
  function defaultPropertiesPanel(propertiesPanelConfig) {
2376
2378
  return !(propertiesPanelConfig && propertiesPanelConfig.parent);
2377
2379
  }
2380
+ function getRemoveButtonTitle(formField, formFields) {
2381
+ const entry = findPaletteEntry(formField.type, formFields);
2382
+ if (!entry) {
2383
+ return 'Remove form field';
2384
+ }
2385
+ return `Remove ${entry.label}`;
2386
+ }
2378
2387
 
2379
2388
  class Renderer {
2380
2389
  constructor(renderConfig, eventBus, formEditor, injector) {
@@ -3291,11 +3300,13 @@ class MoveFormFieldHandler {
3291
3300
  * @param { import('../../../FormEditor').default } formEditor
3292
3301
  * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3293
3302
  * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3303
+ * @param { import('@bpmn-io/form-js-viewer').FormLayouter } formLayouter
3294
3304
  */
3295
- constructor(formEditor, formFieldRegistry, pathRegistry) {
3305
+ constructor(formEditor, formFieldRegistry, pathRegistry, formLayouter) {
3296
3306
  this._formEditor = formEditor;
3297
3307
  this._formFieldRegistry = formFieldRegistry;
3298
3308
  this._pathRegistry = pathRegistry;
3309
+ this._formLayouter = formLayouter;
3299
3310
  }
3300
3311
  execute(context) {
3301
3312
  this.moveFormField(context);
@@ -3342,8 +3353,8 @@ class MoveFormFieldHandler {
3342
3353
  }
3343
3354
  const formField = get(schema, [...sourcePath, sourceIndex]);
3344
3355
 
3345
- // (1) Add to row
3346
- updateRow(formField, targetRow ? targetRow.id : null);
3356
+ // (1) Add to row or create new one
3357
+ updateRow(formField, targetRow ? targetRow.id : this._formLayouter.nextRowId());
3347
3358
 
3348
3359
  // (2) Move form field
3349
3360
  mutate(get(schema, sourcePath), sourceIndex, targetIndex);
@@ -3368,8 +3379,8 @@ class MoveFormFieldHandler {
3368
3379
  get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
3369
3380
  const targetPath = [...targetFormField._path, 'components'];
3370
3381
 
3371
- // (4) Add to row
3372
- updateRow(formField, targetRow ? targetRow.id : null);
3382
+ // (4) Add to row or create new one
3383
+ updateRow(formField, targetRow ? targetRow.id : this._formLayouter.nextRowId());
3373
3384
 
3374
3385
  // (5) Add form field
3375
3386
  arrayAdd$1(get(schema, targetPath), targetIndex, formField);
@@ -3392,7 +3403,7 @@ class MoveFormFieldHandler {
3392
3403
  });
3393
3404
  }
3394
3405
  }
3395
- MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry', 'pathRegistry'];
3406
+ MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry', 'pathRegistry', 'formLayouter'];
3396
3407
 
3397
3408
  class RemoveFormFieldHandler {
3398
3409
  /**
@@ -3982,12 +3993,21 @@ class FormLayoutUpdater extends CommandInterceptor {
3982
3993
  const {
3983
3994
  schema
3984
3995
  } = this._formEditor._getState();
3996
+ const setRowIds = parent => {
3997
+ if (!parent.components || !parent.components.length) {
3998
+ return;
3999
+ }
4000
+ parent.components.forEach(formField => {
4001
+ const row = this._formLayouter.getRowForField(formField);
4002
+ updateRow(formField, row.id);
4003
+
4004
+ // handle children recursively
4005
+ setRowIds(formField);
4006
+ });
4007
+ };
3985
4008
 
3986
4009
  // make sure rows are persisted in schema (e.g. for migration case)
3987
- schema.components.forEach(formField => {
3988
- const row = this._formLayouter.getRowForField(formField);
3989
- updateRow(formField, row.id);
3990
- });
4010
+ setRowIds(schema);
3991
4011
  }
3992
4012
  }
3993
4013
  FormLayoutUpdater.$inject = ['eventBus', 'formLayouter', 'modeling', 'formEditor'];
@@ -4124,12 +4144,61 @@ class ValidateBehavior extends CommandInterceptor {
4124
4144
  }
4125
4145
  ValidateBehavior.$inject = ['eventBus'];
4126
4146
 
4147
+ class ValuesSourceBehavior extends CommandInterceptor {
4148
+ constructor(eventBus) {
4149
+ super(eventBus);
4150
+
4151
+ /**
4152
+ * Cleanup properties on changing the values source.
4153
+ *
4154
+ * 1) Remove other sources, e.g. set `values` => remove `valuesKey` and `valuesExpression`
4155
+ * 2) Remove default values for all other values sources
4156
+ */
4157
+ this.preExecute('formField.edit', function (context) {
4158
+ const {
4159
+ properties
4160
+ } = context;
4161
+ const newProperties = {};
4162
+ if (!isValuesSourceUpdate(properties)) {
4163
+ return;
4164
+ }
4165
+
4166
+ // clean up value sources that are not to going to be set
4167
+ Object.values(VALUES_SOURCES).forEach(source => {
4168
+ const path = VALUES_SOURCES_PATHS[source];
4169
+ if (get(properties, path) == undefined) {
4170
+ newProperties[VALUES_SOURCES_PATHS[source]] = undefined;
4171
+ }
4172
+ });
4173
+
4174
+ // clean up default value
4175
+ if (get(properties, VALUES_SOURCES_PATHS[VALUES_SOURCES.EXPRESSION]) !== undefined || get(properties, VALUES_SOURCES_PATHS[VALUES_SOURCES.INPUT]) !== undefined) {
4176
+ newProperties['defaultValue'] = undefined;
4177
+ }
4178
+ context.properties = {
4179
+ ...properties,
4180
+ ...newProperties
4181
+ };
4182
+ }, true);
4183
+ }
4184
+ }
4185
+ ValuesSourceBehavior.$inject = ['eventBus'];
4186
+
4187
+ // helper ///////////////////
4188
+
4189
+ function isValuesSourceUpdate(properties) {
4190
+ return Object.values(VALUES_SOURCES_PATHS).some(path => {
4191
+ return get(properties, path) !== undefined;
4192
+ });
4193
+ }
4194
+
4127
4195
  var behaviorModule = {
4128
- __init__: ['idBehavior', 'keyBehavior', 'pathBehavior', 'validateBehavior'],
4196
+ __init__: ['idBehavior', 'keyBehavior', 'pathBehavior', 'validateBehavior', 'valuesSourceBehavior'],
4129
4197
  idBehavior: ['type', IdBehavior],
4130
4198
  keyBehavior: ['type', KeyBehavior],
4131
4199
  pathBehavior: ['type', PathBehavior],
4132
- validateBehavior: ['type', ValidateBehavior]
4200
+ validateBehavior: ['type', ValidateBehavior],
4201
+ valuesSourceBehavior: ['type', ValuesSourceBehavior]
4133
4202
  };
4134
4203
 
4135
4204
  /**
@@ -4858,6 +4927,29 @@ FeelIcon$1.defaultProps = {
4858
4927
  fill: "none",
4859
4928
  xmlns: "http://www.w3.org/2000/svg"
4860
4929
  };
4930
+ var HelpIcon = function HelpIcon(props) {
4931
+ return jsxs("svg", {
4932
+ ...props,
4933
+ children: [jsx("path", {
4934
+ d: "M16 2a14 14 0 1 0 14 14A14 14 0 0 0 16 2Zm0 26a12 12 0 1 1 12-12 12 12 0 0 1-12 12Z"
4935
+ }), jsx("circle", {
4936
+ cx: "16",
4937
+ cy: "23.5",
4938
+ r: "1.5"
4939
+ }), jsx("path", {
4940
+ d: "M17 8h-1.5a4.49 4.49 0 0 0-4.5 4.5v.5h2v-.5a2.5 2.5 0 0 1 2.5-2.5H17a2.5 2.5 0 0 1 0 5h-2v4.5h2V17a4.5 4.5 0 0 0 0-9Z"
4941
+ }), jsx("path", {
4942
+ style: {
4943
+ fill: "none"
4944
+ },
4945
+ d: "M0 0h32v32H0z"
4946
+ })]
4947
+ });
4948
+ };
4949
+ HelpIcon.defaultProps = {
4950
+ xmlns: "http://www.w3.org/2000/svg",
4951
+ viewBox: "0 0 32 32"
4952
+ };
4861
4953
  function Header(props) {
4862
4954
  const {
4863
4955
  element,
@@ -5407,6 +5499,7 @@ function Group(props) {
5407
5499
  edited: edited,
5408
5500
  hasErrors: hasErrors
5409
5501
  }), jsx("button", {
5502
+ type: "button",
5410
5503
  title: "Toggle section",
5411
5504
  class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
5412
5505
  children: jsx(ArrowIcon, {
@@ -5587,6 +5680,7 @@ const CodeEditor$1 = forwardRef((props, ref) => {
5587
5680
  ref: inputRef,
5588
5681
  onClick: handleClick
5589
5682
  }), jsx("button", {
5683
+ type: "button",
5590
5684
  title: "Open pop-up editor",
5591
5685
  class: "bio-properties-panel-open-feel-popup",
5592
5686
  onClick: () => onPopupOpen('feelers'),
@@ -5707,6 +5801,7 @@ const CodeEditor = forwardRef((props, ref) => {
5707
5801
  ref: inputRef,
5708
5802
  onClick: handleClick
5709
5803
  }), jsx("button", {
5804
+ type: "button",
5710
5805
  title: "Open pop-up editor",
5711
5806
  class: "bio-properties-panel-open-feel-popup",
5712
5807
  onClick: () => onPopupOpen(),
@@ -5751,6 +5846,7 @@ function FeelIcon(props) {
5751
5846
  }
5752
5847
  };
5753
5848
  return jsx("button", {
5849
+ type: "button",
5754
5850
  class: classnames('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
5755
5851
  onClick: handleClick,
5756
5852
  disabled: feel === 'required' || disabled,
@@ -6197,6 +6293,12 @@ function FeelPopupComponent(props) {
6197
6293
  domNode: popupRef.current
6198
6294
  });
6199
6295
  }, []);
6296
+ useEffect(() => {
6297
+ // Set focus on editor when popup is opened
6298
+ if (editorRef.current) {
6299
+ editorRef.current.focus();
6300
+ }
6301
+ }, [editorRef]);
6200
6302
  return jsxs(Popup, {
6201
6303
  container: container,
6202
6304
  className: "bio-properties-panel-feel-popup",
@@ -6215,10 +6317,21 @@ function FeelPopupComponent(props) {
6215
6317
  height: FEEL_POPUP_HEIGHT,
6216
6318
  width: FEEL_POPUP_WIDTH,
6217
6319
  ref: popupRef,
6218
- children: [jsx(Popup.Title, {
6320
+ children: [jsxs(Popup.Title, {
6219
6321
  title: title,
6220
6322
  emit: emit,
6221
- draggable: true
6323
+ draggable: true,
6324
+ children: [type === 'feel' && jsxs("a", {
6325
+ href: "https://docs.camunda.io/docs/components/modeler/feel/what-is-feel/",
6326
+ target: "_blank",
6327
+ class: "bio-properties-panel-feel-popup__title-link",
6328
+ children: ["Learn FEEL expressions", jsx(HelpIcon, {})]
6329
+ }), type === 'feelers' && jsxs("a", {
6330
+ href: "https://docs.camunda.io/docs/components/modeler/forms/configuration/forms-config-templating-syntax/",
6331
+ target: "_blank",
6332
+ class: "bio-properties-panel-feel-popup__title-link",
6333
+ children: ["Learn templating", jsx(HelpIcon, {})]
6334
+ })]
6222
6335
  }), jsx(Popup.Body, {
6223
6336
  children: jsxs("div", {
6224
6337
  onKeyDownCapture: onKeyDownCapture,
@@ -6250,6 +6363,7 @@ function FeelPopupComponent(props) {
6250
6363
  })
6251
6364
  }), jsx(Popup.Footer, {
6252
6365
  children: jsx("button", {
6366
+ type: "button",
6253
6367
  onClick: onClose,
6254
6368
  title: "Close pop-up editor",
6255
6369
  class: "bio-properties-panel-feel-popup__close-btn",
@@ -7491,12 +7605,14 @@ function CollapsibleEntry(props) {
7491
7605
  class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
7492
7606
  children: label || placeholderLabel
7493
7607
  }), jsx("button", {
7608
+ type: "button",
7494
7609
  title: "Toggle list item",
7495
7610
  class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
7496
7611
  children: jsx(ArrowIcon, {
7497
7612
  class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
7498
7613
  })
7499
7614
  }), remove ? jsx("button", {
7615
+ type: "button",
7500
7616
  title: "Delete item",
7501
7617
  class: "bio-properties-panel-remove-entry",
7502
7618
  onClick: remove,
@@ -7698,6 +7814,7 @@ function ListGroup(props) {
7698
7814
  }), jsxs("div", {
7699
7815
  class: "bio-properties-panel-group-header-buttons",
7700
7816
  children: [add ? jsxs("button", {
7817
+ type: "button",
7701
7818
  title: "Create new list item",
7702
7819
  class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
7703
7820
  onClick: handleAddClick,
@@ -7710,6 +7827,7 @@ function ListGroup(props) {
7710
7827
  class: classnames('bio-properties-panel-list-badge', hasError ? 'bio-properties-panel-list-badge--error' : ''),
7711
7828
  children: items.length
7712
7829
  }) : null, hasItems ? jsx("button", {
7830
+ type: "button",
7713
7831
  title: "Toggle section",
7714
7832
  class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
7715
7833
  children: jsx(ArrowIcon, {
@@ -10412,11 +10530,7 @@ function ValuesSourceSelect(props) {
10412
10530
  const setValue = value => {
10413
10531
  let newField = field;
10414
10532
  const newProperties = {};
10415
- Object.values(VALUES_SOURCES).forEach(source => {
10416
- // Clear all values source definitions and default the newly selected one
10417
- const newValue = value === source ? VALUES_SOURCES_DEFAULTS[source] : undefined;
10418
- newProperties[VALUES_SOURCES_PATHS[source]] = newValue;
10419
- });
10533
+ newProperties[VALUES_SOURCES_PATHS[value]] = VALUES_SOURCES_DEFAULTS[value];
10420
10534
  newField = editField(field, newProperties);
10421
10535
  return newField;
10422
10536
  };