@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.
@@ -216,6 +216,17 @@
216
216
  display: none;
217
217
  }
218
218
 
219
+ .fjs-no-json-lint .cm-activeLine,
220
+ .fjs-no-json-lint .cm-activeLineGutter {
221
+ background: none;
222
+ }
223
+
224
+ .fjs-no-json-lint .cm-placeholder {
225
+ font-size: 12px;
226
+ line-height: 16px;
227
+ color: var(--cds-text-placeholder, var(--color-grey-225-10-35));
228
+ }
229
+
219
230
  .fjs-editor-container .fjs-form-editor {
220
231
  display: flex;
221
232
  flex: 1;
@@ -194,6 +194,17 @@
194
194
  display: none;
195
195
  }
196
196
 
197
+ .fjs-no-json-lint .cm-activeLine,
198
+ .fjs-no-json-lint .cm-activeLineGutter {
199
+ background: none;
200
+ }
201
+
202
+ .fjs-no-json-lint .cm-placeholder {
203
+ font-size: 12px;
204
+ line-height: 16px;
205
+ color: var(--cds-text-placeholder, var(--color-grey-225-10-35));
206
+ }
207
+
197
208
  .fjs-editor-container .fjs-form-editor {
198
209
  display: flex;
199
210
  flex: 1;
@@ -2052,6 +2063,8 @@ textarea.bio-properties-panel-input {
2052
2063
  .bio-properties-panel-popup .bio-properties-panel-popup__footer {
2053
2064
  padding: 12px;
2054
2065
  display: flex;
2066
+ justify-content: center;
2067
+ align-items: center;
2055
2068
  }
2056
2069
 
2057
2070
  .bio-properties-panel-popup .bio-properties-panel-popup__body:not(:first-child) {
@@ -2059,11 +2072,12 @@ textarea.bio-properties-panel-input {
2059
2072
  }
2060
2073
 
2061
2074
  .bio-properties-panel-popup .bio-properties-panel-popup__header {
2075
+ --popup-header-line-height: 16px;
2062
2076
  background-color: var(--popup-header-background-color);
2063
2077
  margin: 0;
2064
2078
  font-size: 12px;
2065
2079
  font-weight: 400;
2066
- line-height: 16px;
2080
+ line-height: var(--popup-header-line-height);
2067
2081
  text-align: left;
2068
2082
  color: var(--popup-title-color);
2069
2083
  }
@@ -2091,7 +2105,7 @@ textarea.bio-properties-panel-input {
2091
2105
  text-transform: capitalize;
2092
2106
  }
2093
2107
 
2094
- .bio-properties-panel-popup .bio-properties-panel-popup__header svg {
2108
+ .bio-properties-panel-popup .bio-properties-panel-popup__header .bio-properties-panel-popup__drag-handle svg {
2095
2109
  margin-left: -4px;
2096
2110
  }
2097
2111
 
@@ -2122,6 +2136,18 @@ textarea.bio-properties-panel-input {
2122
2136
  width: 100%;
2123
2137
  }
2124
2138
 
2139
+ .bio-properties-panel-feel-popup__title-link {
2140
+ margin-left: auto;
2141
+ display: flex;
2142
+ }
2143
+
2144
+ .bio-properties-panel-feel-popup__title-link svg {
2145
+ width: var(--popup-header-line-height);
2146
+ height: var(--popup-header-line-height);
2147
+ fill: currentColor;
2148
+ margin: 0 0.5em;
2149
+ }
2150
+
2125
2151
  .bio-properties-panel-feel-popup .bio-properties-panel-feel-editor-container {
2126
2152
  display: flex;
2127
2153
  min-width: 100%;
@@ -1271,6 +1271,8 @@ textarea.bio-properties-panel-input {
1271
1271
  .bio-properties-panel-popup .bio-properties-panel-popup__footer {
1272
1272
  padding: 12px;
1273
1273
  display: flex;
1274
+ justify-content: center;
1275
+ align-items: center;
1274
1276
  }
1275
1277
 
1276
1278
  .bio-properties-panel-popup .bio-properties-panel-popup__body:not(:first-child) {
@@ -1278,11 +1280,12 @@ textarea.bio-properties-panel-input {
1278
1280
  }
1279
1281
 
1280
1282
  .bio-properties-panel-popup .bio-properties-panel-popup__header {
1283
+ --popup-header-line-height: 16px;
1281
1284
  background-color: var(--popup-header-background-color);
1282
1285
  margin: 0;
1283
1286
  font-size: 12px;
1284
1287
  font-weight: 400;
1285
- line-height: 16px;
1288
+ line-height: var(--popup-header-line-height);
1286
1289
  text-align: left;
1287
1290
  color: var(--popup-title-color);
1288
1291
  }
@@ -1310,7 +1313,7 @@ textarea.bio-properties-panel-input {
1310
1313
  text-transform: capitalize;
1311
1314
  }
1312
1315
 
1313
- .bio-properties-panel-popup .bio-properties-panel-popup__header svg {
1316
+ .bio-properties-panel-popup .bio-properties-panel-popup__header .bio-properties-panel-popup__drag-handle svg {
1314
1317
  margin-left: -4px;
1315
1318
  }
1316
1319
 
@@ -1341,6 +1344,18 @@ textarea.bio-properties-panel-input {
1341
1344
  width: 100%;
1342
1345
  }
1343
1346
 
1347
+ .bio-properties-panel-feel-popup__title-link {
1348
+ margin-left: auto;
1349
+ display: flex;
1350
+ }
1351
+
1352
+ .bio-properties-panel-feel-popup__title-link svg {
1353
+ width: var(--popup-header-line-height);
1354
+ height: var(--popup-header-line-height);
1355
+ fill: currentColor;
1356
+ margin: 0 0.5em;
1357
+ }
1358
+
1344
1359
  .bio-properties-panel-feel-popup .bio-properties-panel-feel-editor-container {
1345
1360
  display: flex;
1346
1361
  min-width: 100%;
package/dist/index.cjs CHANGED
@@ -1990,6 +1990,7 @@ function Element$1(props) {
1990
1990
  const eventBus = useService$1('eventBus'),
1991
1991
  formEditor = useService$1('formEditor'),
1992
1992
  formFieldRegistry = useService$1('formFieldRegistry'),
1993
+ formFields = useService$1('formFields'),
1993
1994
  modeling = useService$1('modeling'),
1994
1995
  selection = useService$1('selection');
1995
1996
  const {
@@ -2075,6 +2076,7 @@ function Element$1(props) {
2075
2076
  field: field
2076
2077
  }), jsxRuntime.jsx(ContextPad, {
2077
2078
  children: selection.isSelected(field) && field.type !== 'default' ? jsxRuntime.jsx("button", {
2079
+ title: getRemoveButtonTitle(field, formFields),
2078
2080
  class: "fjs-context-pad-item",
2079
2081
  onClick: onRemove,
2080
2082
  children: jsxRuntime.jsx(DeleteIcon$1, {})
@@ -2395,6 +2397,13 @@ function findPaletteEntry(type, formFields) {
2395
2397
  function defaultPropertiesPanel(propertiesPanelConfig) {
2396
2398
  return !(propertiesPanelConfig && propertiesPanelConfig.parent);
2397
2399
  }
2400
+ function getRemoveButtonTitle(formField, formFields) {
2401
+ const entry = findPaletteEntry(formField.type, formFields);
2402
+ if (!entry) {
2403
+ return 'Remove form field';
2404
+ }
2405
+ return `Remove ${entry.label}`;
2406
+ }
2398
2407
 
2399
2408
  class Renderer {
2400
2409
  constructor(renderConfig, eventBus, formEditor, injector) {
@@ -3311,11 +3320,13 @@ class MoveFormFieldHandler {
3311
3320
  * @param { import('../../../FormEditor').default } formEditor
3312
3321
  * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3313
3322
  * @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
3323
+ * @param { import('@bpmn-io/form-js-viewer').FormLayouter } formLayouter
3314
3324
  */
3315
- constructor(formEditor, formFieldRegistry, pathRegistry) {
3325
+ constructor(formEditor, formFieldRegistry, pathRegistry, formLayouter) {
3316
3326
  this._formEditor = formEditor;
3317
3327
  this._formFieldRegistry = formFieldRegistry;
3318
3328
  this._pathRegistry = pathRegistry;
3329
+ this._formLayouter = formLayouter;
3319
3330
  }
3320
3331
  execute(context) {
3321
3332
  this.moveFormField(context);
@@ -3362,8 +3373,8 @@ class MoveFormFieldHandler {
3362
3373
  }
3363
3374
  const formField = minDash.get(schema, [...sourcePath, sourceIndex]);
3364
3375
 
3365
- // (1) Add to row
3366
- updateRow(formField, targetRow ? targetRow.id : null);
3376
+ // (1) Add to row or create new one
3377
+ updateRow(formField, targetRow ? targetRow.id : this._formLayouter.nextRowId());
3367
3378
 
3368
3379
  // (2) Move form field
3369
3380
  arrayMove.mutate(minDash.get(schema, sourcePath), sourceIndex, targetIndex);
@@ -3388,8 +3399,8 @@ class MoveFormFieldHandler {
3388
3399
  minDash.get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
3389
3400
  const targetPath = [...targetFormField._path, 'components'];
3390
3401
 
3391
- // (4) Add to row
3392
- updateRow(formField, targetRow ? targetRow.id : null);
3402
+ // (4) Add to row or create new one
3403
+ updateRow(formField, targetRow ? targetRow.id : this._formLayouter.nextRowId());
3393
3404
 
3394
3405
  // (5) Add form field
3395
3406
  arrayAdd$1(minDash.get(schema, targetPath), targetIndex, formField);
@@ -3412,7 +3423,7 @@ class MoveFormFieldHandler {
3412
3423
  });
3413
3424
  }
3414
3425
  }
3415
- MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry', 'pathRegistry'];
3426
+ MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry', 'pathRegistry', 'formLayouter'];
3416
3427
 
3417
3428
  class RemoveFormFieldHandler {
3418
3429
  /**
@@ -4002,12 +4013,21 @@ class FormLayoutUpdater extends CommandInterceptor {
4002
4013
  const {
4003
4014
  schema
4004
4015
  } = this._formEditor._getState();
4016
+ const setRowIds = parent => {
4017
+ if (!parent.components || !parent.components.length) {
4018
+ return;
4019
+ }
4020
+ parent.components.forEach(formField => {
4021
+ const row = this._formLayouter.getRowForField(formField);
4022
+ updateRow(formField, row.id);
4023
+
4024
+ // handle children recursively
4025
+ setRowIds(formField);
4026
+ });
4027
+ };
4005
4028
 
4006
4029
  // make sure rows are persisted in schema (e.g. for migration case)
4007
- schema.components.forEach(formField => {
4008
- const row = this._formLayouter.getRowForField(formField);
4009
- updateRow(formField, row.id);
4010
- });
4030
+ setRowIds(schema);
4011
4031
  }
4012
4032
  }
4013
4033
  FormLayoutUpdater.$inject = ['eventBus', 'formLayouter', 'modeling', 'formEditor'];
@@ -4144,12 +4164,61 @@ class ValidateBehavior extends CommandInterceptor {
4144
4164
  }
4145
4165
  ValidateBehavior.$inject = ['eventBus'];
4146
4166
 
4167
+ class ValuesSourceBehavior extends CommandInterceptor {
4168
+ constructor(eventBus) {
4169
+ super(eventBus);
4170
+
4171
+ /**
4172
+ * Cleanup properties on changing the values source.
4173
+ *
4174
+ * 1) Remove other sources, e.g. set `values` => remove `valuesKey` and `valuesExpression`
4175
+ * 2) Remove default values for all other values sources
4176
+ */
4177
+ this.preExecute('formField.edit', function (context) {
4178
+ const {
4179
+ properties
4180
+ } = context;
4181
+ const newProperties = {};
4182
+ if (!isValuesSourceUpdate(properties)) {
4183
+ return;
4184
+ }
4185
+
4186
+ // clean up value sources that are not to going to be set
4187
+ Object.values(formJsViewer.VALUES_SOURCES).forEach(source => {
4188
+ const path = formJsViewer.VALUES_SOURCES_PATHS[source];
4189
+ if (minDash.get(properties, path) == undefined) {
4190
+ newProperties[formJsViewer.VALUES_SOURCES_PATHS[source]] = undefined;
4191
+ }
4192
+ });
4193
+
4194
+ // clean up default value
4195
+ if (minDash.get(properties, formJsViewer.VALUES_SOURCES_PATHS[formJsViewer.VALUES_SOURCES.EXPRESSION]) !== undefined || minDash.get(properties, formJsViewer.VALUES_SOURCES_PATHS[formJsViewer.VALUES_SOURCES.INPUT]) !== undefined) {
4196
+ newProperties['defaultValue'] = undefined;
4197
+ }
4198
+ context.properties = {
4199
+ ...properties,
4200
+ ...newProperties
4201
+ };
4202
+ }, true);
4203
+ }
4204
+ }
4205
+ ValuesSourceBehavior.$inject = ['eventBus'];
4206
+
4207
+ // helper ///////////////////
4208
+
4209
+ function isValuesSourceUpdate(properties) {
4210
+ return Object.values(formJsViewer.VALUES_SOURCES_PATHS).some(path => {
4211
+ return minDash.get(properties, path) !== undefined;
4212
+ });
4213
+ }
4214
+
4147
4215
  var behaviorModule = {
4148
- __init__: ['idBehavior', 'keyBehavior', 'pathBehavior', 'validateBehavior'],
4216
+ __init__: ['idBehavior', 'keyBehavior', 'pathBehavior', 'validateBehavior', 'valuesSourceBehavior'],
4149
4217
  idBehavior: ['type', IdBehavior],
4150
4218
  keyBehavior: ['type', KeyBehavior],
4151
4219
  pathBehavior: ['type', PathBehavior],
4152
- validateBehavior: ['type', ValidateBehavior]
4220
+ validateBehavior: ['type', ValidateBehavior],
4221
+ valuesSourceBehavior: ['type', ValuesSourceBehavior]
4153
4222
  };
4154
4223
 
4155
4224
  /**
@@ -4878,6 +4947,29 @@ FeelIcon$1.defaultProps = {
4878
4947
  fill: "none",
4879
4948
  xmlns: "http://www.w3.org/2000/svg"
4880
4949
  };
4950
+ var HelpIcon = function HelpIcon(props) {
4951
+ return jsxRuntime.jsxs("svg", {
4952
+ ...props,
4953
+ children: [jsxRuntime.jsx("path", {
4954
+ 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"
4955
+ }), jsxRuntime.jsx("circle", {
4956
+ cx: "16",
4957
+ cy: "23.5",
4958
+ r: "1.5"
4959
+ }), jsxRuntime.jsx("path", {
4960
+ 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"
4961
+ }), jsxRuntime.jsx("path", {
4962
+ style: {
4963
+ fill: "none"
4964
+ },
4965
+ d: "M0 0h32v32H0z"
4966
+ })]
4967
+ });
4968
+ };
4969
+ HelpIcon.defaultProps = {
4970
+ xmlns: "http://www.w3.org/2000/svg",
4971
+ viewBox: "0 0 32 32"
4972
+ };
4881
4973
  function Header(props) {
4882
4974
  const {
4883
4975
  element,
@@ -5427,6 +5519,7 @@ function Group(props) {
5427
5519
  edited: edited,
5428
5520
  hasErrors: hasErrors
5429
5521
  }), jsxRuntime.jsx("button", {
5522
+ type: "button",
5430
5523
  title: "Toggle section",
5431
5524
  class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
5432
5525
  children: jsxRuntime.jsx(ArrowIcon, {
@@ -5607,6 +5700,7 @@ const CodeEditor$1 = React.forwardRef((props, ref) => {
5607
5700
  ref: inputRef,
5608
5701
  onClick: handleClick
5609
5702
  }), jsxRuntime.jsx("button", {
5703
+ type: "button",
5610
5704
  title: "Open pop-up editor",
5611
5705
  class: "bio-properties-panel-open-feel-popup",
5612
5706
  onClick: () => onPopupOpen('feelers'),
@@ -5727,6 +5821,7 @@ const CodeEditor = React.forwardRef((props, ref) => {
5727
5821
  ref: inputRef,
5728
5822
  onClick: handleClick
5729
5823
  }), jsxRuntime.jsx("button", {
5824
+ type: "button",
5730
5825
  title: "Open pop-up editor",
5731
5826
  class: "bio-properties-panel-open-feel-popup",
5732
5827
  onClick: () => onPopupOpen(),
@@ -5771,6 +5866,7 @@ function FeelIcon(props) {
5771
5866
  }
5772
5867
  };
5773
5868
  return jsxRuntime.jsx("button", {
5869
+ type: "button",
5774
5870
  class: classnames('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
5775
5871
  onClick: handleClick,
5776
5872
  disabled: feel === 'required' || disabled,
@@ -6217,6 +6313,12 @@ function FeelPopupComponent(props) {
6217
6313
  domNode: popupRef.current
6218
6314
  });
6219
6315
  }, []);
6316
+ hooks.useEffect(() => {
6317
+ // Set focus on editor when popup is opened
6318
+ if (editorRef.current) {
6319
+ editorRef.current.focus();
6320
+ }
6321
+ }, [editorRef]);
6220
6322
  return jsxRuntime.jsxs(Popup, {
6221
6323
  container: container,
6222
6324
  className: "bio-properties-panel-feel-popup",
@@ -6235,10 +6337,21 @@ function FeelPopupComponent(props) {
6235
6337
  height: FEEL_POPUP_HEIGHT,
6236
6338
  width: FEEL_POPUP_WIDTH,
6237
6339
  ref: popupRef,
6238
- children: [jsxRuntime.jsx(Popup.Title, {
6340
+ children: [jsxRuntime.jsxs(Popup.Title, {
6239
6341
  title: title,
6240
6342
  emit: emit,
6241
- draggable: true
6343
+ draggable: true,
6344
+ children: [type === 'feel' && jsxRuntime.jsxs("a", {
6345
+ href: "https://docs.camunda.io/docs/components/modeler/feel/what-is-feel/",
6346
+ target: "_blank",
6347
+ class: "bio-properties-panel-feel-popup__title-link",
6348
+ children: ["Learn FEEL expressions", jsxRuntime.jsx(HelpIcon, {})]
6349
+ }), type === 'feelers' && jsxRuntime.jsxs("a", {
6350
+ href: "https://docs.camunda.io/docs/components/modeler/forms/configuration/forms-config-templating-syntax/",
6351
+ target: "_blank",
6352
+ class: "bio-properties-panel-feel-popup__title-link",
6353
+ children: ["Learn templating", jsxRuntime.jsx(HelpIcon, {})]
6354
+ })]
6242
6355
  }), jsxRuntime.jsx(Popup.Body, {
6243
6356
  children: jsxRuntime.jsxs("div", {
6244
6357
  onKeyDownCapture: onKeyDownCapture,
@@ -6270,6 +6383,7 @@ function FeelPopupComponent(props) {
6270
6383
  })
6271
6384
  }), jsxRuntime.jsx(Popup.Footer, {
6272
6385
  children: jsxRuntime.jsx("button", {
6386
+ type: "button",
6273
6387
  onClick: onClose,
6274
6388
  title: "Close pop-up editor",
6275
6389
  class: "bio-properties-panel-feel-popup__close-btn",
@@ -7511,12 +7625,14 @@ function CollapsibleEntry(props) {
7511
7625
  class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
7512
7626
  children: label || placeholderLabel
7513
7627
  }), jsxRuntime.jsx("button", {
7628
+ type: "button",
7514
7629
  title: "Toggle list item",
7515
7630
  class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
7516
7631
  children: jsxRuntime.jsx(ArrowIcon, {
7517
7632
  class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
7518
7633
  })
7519
7634
  }), remove ? jsxRuntime.jsx("button", {
7635
+ type: "button",
7520
7636
  title: "Delete item",
7521
7637
  class: "bio-properties-panel-remove-entry",
7522
7638
  onClick: remove,
@@ -7718,6 +7834,7 @@ function ListGroup(props) {
7718
7834
  }), jsxRuntime.jsxs("div", {
7719
7835
  class: "bio-properties-panel-group-header-buttons",
7720
7836
  children: [add ? jsxRuntime.jsxs("button", {
7837
+ type: "button",
7721
7838
  title: "Create new list item",
7722
7839
  class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
7723
7840
  onClick: handleAddClick,
@@ -7730,6 +7847,7 @@ function ListGroup(props) {
7730
7847
  class: classnames('bio-properties-panel-list-badge', hasError ? 'bio-properties-panel-list-badge--error' : ''),
7731
7848
  children: items.length
7732
7849
  }) : null, hasItems ? jsxRuntime.jsx("button", {
7850
+ type: "button",
7733
7851
  title: "Toggle section",
7734
7852
  class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
7735
7853
  children: jsxRuntime.jsx(ArrowIcon, {
@@ -10432,11 +10550,7 @@ function ValuesSourceSelect(props) {
10432
10550
  const setValue = value => {
10433
10551
  let newField = field;
10434
10552
  const newProperties = {};
10435
- Object.values(formJsViewer.VALUES_SOURCES).forEach(source => {
10436
- // Clear all values source definitions and default the newly selected one
10437
- const newValue = value === source ? formJsViewer.VALUES_SOURCES_DEFAULTS[source] : undefined;
10438
- newProperties[formJsViewer.VALUES_SOURCES_PATHS[source]] = newValue;
10439
- });
10553
+ newProperties[formJsViewer.VALUES_SOURCES_PATHS[value]] = formJsViewer.VALUES_SOURCES_DEFAULTS[value];
10440
10554
  newField = editField(field, newProperties);
10441
10555
  return newField;
10442
10556
  };