@bpmn-io/form-js-editor 1.7.3 → 1.8.1

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,5 +1,5 @@
1
1
  import Ids from 'ids';
2
- import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Label as Label$3, IFrame, Text as Text$1, Html, Table, FormFields, sanitizeImageSource, getAncestryList, FormContext, FormRenderContext, FormComponent, 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';
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
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';
5
5
  import classnames from 'classnames';
@@ -127,6 +127,8 @@ var slice = Array.prototype.slice;
127
127
  * var sum = eventBus.fire('sum', 1, 2);
128
128
  * console.log(sum); // 3
129
129
  * ```
130
+ *
131
+ * @template [EventMap=null]
130
132
  */
131
133
  function EventBus() {
132
134
  /**
@@ -140,6 +142,8 @@ function EventBus() {
140
142
  }
141
143
 
142
144
  /**
145
+ * @overlord
146
+ *
143
147
  * Register an event listener for events with the given name.
144
148
  *
145
149
  * The callback will be invoked with `event, ...additionalArguments`
@@ -158,6 +162,25 @@ function EventBus() {
158
162
  * @param {EventBusEventCallback<T>} callback
159
163
  * @param {any} [that] callback context
160
164
  */
165
+ /**
166
+ * Register an event listener for events with the given name.
167
+ *
168
+ * The callback will be invoked with `event, ...additionalArguments`
169
+ * that have been passed to {@link EventBus#fire}.
170
+ *
171
+ * Returning false from a listener will prevent the events default action
172
+ * (if any is specified). To stop an event from being processed further in
173
+ * other listeners execute {@link Event#stopPropagation}.
174
+ *
175
+ * Returning anything but `undefined` from a listener will stop the listener propagation.
176
+ *
177
+ * @template {keyof EventMap} EventName
178
+ *
179
+ * @param {EventName} events to subscribe to
180
+ * @param {number} [priority=1000] listen priority
181
+ * @param {EventBusEventCallback<EventMap[EventName]>} callback
182
+ * @param {any} [that] callback context
183
+ */
161
184
  EventBus.prototype.on = function (events, priority, callback, that) {
162
185
  events = isArray(events) ? events : [events];
163
186
  if (isFunction(priority)) {
@@ -188,6 +211,8 @@ EventBus.prototype.on = function (events, priority, callback, that) {
188
211
  };
189
212
 
190
213
  /**
214
+ * @overlord
215
+ *
191
216
  * Register an event listener that is called only once.
192
217
  *
193
218
  * @template T
@@ -197,6 +222,16 @@ EventBus.prototype.on = function (events, priority, callback, that) {
197
222
  * @param {EventBusEventCallback<T>} callback
198
223
  * @param {any} [that] callback context
199
224
  */
225
+ /**
226
+ * Register an event listener that is called only once.
227
+ *
228
+ * @template {keyof EventMap} EventName
229
+ *
230
+ * @param {EventName} events to subscribe to
231
+ * @param {number} [priority=1000] listen priority
232
+ * @param {EventBusEventCallback<EventMap[EventName]>} callback
233
+ * @param {any} [that] callback context
234
+ */
200
235
  EventBus.prototype.once = function (events, priority, callback, that) {
201
236
  var self = this;
202
237
  if (isFunction(priority)) {
@@ -1122,7 +1157,36 @@ function EditorTable(props) {
1122
1157
  }
1123
1158
  EditorTable.config = Table.config;
1124
1159
 
1125
- const editorFormFields = [EditorIFrame, EditorText, EditorHtml, EditorTable];
1160
+ const type = 'expression';
1161
+ function EditorExpressionField(props) {
1162
+ const {
1163
+ field
1164
+ } = props;
1165
+ const {
1166
+ expression = ''
1167
+ } = field;
1168
+ const Icon = iconsByType('expression');
1169
+ const expressionLanguage = useService$1('expressionLanguage');
1170
+ let placeholderContent = 'Expression is empty';
1171
+ if (expression.trim() && expressionLanguage.isExpression(expression)) {
1172
+ placeholderContent = 'Expression';
1173
+ }
1174
+ return jsx("div", {
1175
+ class: editorFormFieldClasses(type),
1176
+ children: jsxs("div", {
1177
+ class: "fjs-form-field-placeholder",
1178
+ children: [jsx(Icon, {
1179
+ viewBox: "0 0 54 54"
1180
+ }), placeholderContent]
1181
+ })
1182
+ });
1183
+ }
1184
+ EditorExpressionField.config = {
1185
+ ...ExpressionField.config,
1186
+ escapeGridRender: false
1187
+ };
1188
+
1189
+ const editorFormFields = [EditorIFrame, EditorText, EditorHtml, EditorTable, EditorExpressionField];
1126
1190
 
1127
1191
  class EditorFormFields extends FormFields {
1128
1192
  constructor() {
@@ -1417,7 +1481,7 @@ function getIndefiniteArticle(type) {
1417
1481
  }
1418
1482
 
1419
1483
  const PALETTE_GROUPS = [{
1420
- label: 'Basic input',
1484
+ label: 'Input',
1421
1485
  id: 'basic-input'
1422
1486
  }, {
1423
1487
  label: 'Selection',
@@ -2139,7 +2203,6 @@ function Empty(props) {
2139
2203
  }
2140
2204
  function Element$1(props) {
2141
2205
  const eventBus = useService$1('eventBus'),
2142
- formEditor = useService$1('formEditor'),
2143
2206
  formFieldRegistry = useService$1('formFieldRegistry'),
2144
2207
  formFields = useService$1('formFields'),
2145
2208
  modeling = useService$1('modeling'),
@@ -2161,18 +2224,24 @@ function Element$1(props) {
2161
2224
  function scrollIntoView({
2162
2225
  selection
2163
2226
  }) {
2164
- if (!selection || selection.id !== id || !ref.current) {
2227
+ const scrollContainer = getScrollContainer(ref.current);
2228
+ if (!selection || selection.type === 'default' || selection.id !== id || !scrollContainer || !ref.current) {
2165
2229
  return;
2166
2230
  }
2167
- const elementBounds = ref.current.getBoundingClientRect(),
2168
- containerBounds = formEditor._container.getBoundingClientRect();
2169
- if (elementBounds.top < 0 || elementBounds.top > containerBounds.bottom) {
2170
- ref.current.scrollIntoView();
2231
+ const elementBounds = ref.current.getBoundingClientRect();
2232
+ const scrollContainerBounds = scrollContainer.getBoundingClientRect();
2233
+ const isElementLarger = elementBounds.height > scrollContainerBounds.height;
2234
+ const isNotFullyVisible = elementBounds.bottom > scrollContainerBounds.bottom || elementBounds.top < scrollContainerBounds.top;
2235
+ if (isNotFullyVisible && !isElementLarger) {
2236
+ ref.current.scrollIntoView({
2237
+ behavior: 'auto',
2238
+ block: 'nearest'
2239
+ });
2171
2240
  }
2172
2241
  }
2173
2242
  eventBus.on('selection.changed', scrollIntoView);
2174
2243
  return () => eventBus.off('selection.changed', scrollIntoView);
2175
- }, [eventBus, formEditor._container, id]);
2244
+ }, [eventBus, id]);
2176
2245
  useLayoutEffect(() => {
2177
2246
  if (selection.isSelected(field)) {
2178
2247
  ref.current.focus();
@@ -2194,14 +2263,15 @@ function Element$1(props) {
2194
2263
  if (isSelected) {
2195
2264
  classes.push('fjs-editor-selected');
2196
2265
  }
2197
- if (showOutline) {
2198
- classes.push('fjs-outlined');
2266
+ const grouplike = ['group', 'dynamiclist'].includes(type);
2267
+ if (grouplike) {
2268
+ classes.push(showOutline ? 'fjs-outlined' : 'fjs-dashed-outlined');
2199
2269
  }
2200
2270
  if (hovered) {
2201
2271
  classes.push('fjs-editor-hovered');
2202
2272
  }
2203
2273
  return classes.join(' ');
2204
- }, [hovered, isSelected, props.class, showOutline]);
2274
+ }, [hovered, isSelected, props.class, showOutline, type]);
2205
2275
  const onRemove = event => {
2206
2276
  event.stopPropagation();
2207
2277
  const parentField = formFieldRegistry.get(field._parent);
@@ -2833,9 +2903,9 @@ EditorActions.prototype.unregister = function (action) {
2833
2903
  };
2834
2904
 
2835
2905
  /**
2836
- * Returns the number of actions that are currently registered
2906
+ * Returns the identifiers of all currently registered editor actions
2837
2907
  *
2838
- * @return {number}
2908
+ * @return {string[]}
2839
2909
  */
2840
2910
  EditorActions.prototype.getActions = function () {
2841
2911
  return Object.keys(this._actions);
@@ -3088,7 +3158,7 @@ Keyboard.prototype._isEventIgnored = function (event) {
3088
3158
  if (event.defaultPrevented) {
3089
3159
  return true;
3090
3160
  }
3091
- return isInput(event.target) && this._isModifiedKeyIgnored(event);
3161
+ return (isInput(event.target) || isButton(event.target) && isKey([' ', 'Enter'], event)) && this._isModifiedKeyIgnored(event);
3092
3162
  };
3093
3163
  Keyboard.prototype._isModifiedKeyIgnored = function (event) {
3094
3164
  if (!isCmd(event)) {
@@ -3185,6 +3255,9 @@ Keyboard.prototype.isKey = isKey;
3185
3255
  function isInput(target) {
3186
3256
  return target && (matches(target, 'input, textarea') || target.contentEditable === 'true');
3187
3257
  }
3258
+ function isButton(target) {
3259
+ return target && matches(target, 'button, input[type=submit], input[type=button], a[href], [aria-role=button]');
3260
+ }
3188
3261
 
3189
3262
  var LOW_PRIORITY$1 = 500;
3190
3263
 
@@ -5159,6 +5232,7 @@ class PaletteRenderer extends SectionModuleBase {
5159
5232
  PaletteRenderer.$inject = ['eventBus'];
5160
5233
 
5161
5234
  const PaletteModule = {
5235
+ __init__: ['palette'],
5162
5236
  palette: ['type', PaletteRenderer]
5163
5237
  };
5164
5238
 
@@ -8954,7 +9028,7 @@ function useVariables() {
8954
9028
  return getSchemaVariables(schema);
8955
9029
  }
8956
9030
 
8957
- const headerlessTypes = ['spacer', 'separator', 'html'];
9031
+ const headerlessTypes = ['spacer', 'separator', 'expression', 'html'];
8958
9032
  const PropertiesPanelHeaderProvider = {
8959
9033
  getElementLabel: field => {
8960
9034
  const {
@@ -10773,6 +10847,83 @@ const validateNumberEntries = value => {
10773
10847
  }
10774
10848
  };
10775
10849
 
10850
+ function ExpressionFieldEntries(props) {
10851
+ const {
10852
+ editField,
10853
+ field,
10854
+ id
10855
+ } = props;
10856
+ const entries = [];
10857
+ entries.push({
10858
+ id: `${id}-expression`,
10859
+ component: ExpressionFieldExpression,
10860
+ isEdited: isEdited$6,
10861
+ editField,
10862
+ field,
10863
+ isDefaultVisible: field => field.type === 'expression'
10864
+ });
10865
+ entries.push({
10866
+ id: `${id}-computeOn`,
10867
+ component: ExpressionFieldComputeOn,
10868
+ isEdited: isEdited$3,
10869
+ editField,
10870
+ field,
10871
+ isDefaultVisible: field => field.type === 'expression'
10872
+ });
10873
+ return entries;
10874
+ }
10875
+ function ExpressionFieldExpression(props) {
10876
+ const {
10877
+ editField,
10878
+ field,
10879
+ id
10880
+ } = props;
10881
+ const debounce = useService('debounce');
10882
+ const variables = useVariables().map(name => ({
10883
+ name
10884
+ }));
10885
+ const getValue = () => field.expression || '';
10886
+ const setValue = value => {
10887
+ editField(field, ['expression'], value);
10888
+ };
10889
+ return FeelEntry({
10890
+ debounce,
10891
+ description: 'Define an expression to calculate the value of this field',
10892
+ element: field,
10893
+ feel: 'required',
10894
+ getValue,
10895
+ id,
10896
+ label: 'Target value',
10897
+ setValue,
10898
+ variables
10899
+ });
10900
+ }
10901
+ function ExpressionFieldComputeOn(props) {
10902
+ const {
10903
+ editField,
10904
+ field,
10905
+ id
10906
+ } = props;
10907
+ const getValue = () => field.computeOn || '';
10908
+ const setValue = value => {
10909
+ editField(field, ['computeOn'], value);
10910
+ };
10911
+ const getOptions = () => [{
10912
+ value: 'change',
10913
+ label: 'Value changes'
10914
+ }, {
10915
+ value: 'presubmit',
10916
+ label: 'Form submission'
10917
+ }];
10918
+ return SelectEntry({
10919
+ id,
10920
+ label: 'Compute on',
10921
+ getValue,
10922
+ setValue,
10923
+ getOptions
10924
+ });
10925
+ }
10926
+
10776
10927
  function NumberSerializationEntry(props) {
10777
10928
  const {
10778
10929
  editField,
@@ -11733,14 +11884,22 @@ function Condition(props) {
11733
11884
  hide: value
11734
11885
  });
11735
11886
  };
11887
+ let label = 'Hide if';
11888
+ let description = 'Condition under which the field is hidden';
11889
+
11890
+ // special case for expression fields which do not render
11891
+ if (field.type === 'expression') {
11892
+ label = 'Deactivate if';
11893
+ description = 'Condition under which the field is deactivated';
11894
+ }
11736
11895
  return FeelEntry({
11737
11896
  debounce,
11738
- description: 'Condition under which the field is hidden',
11897
+ description,
11739
11898
  element: field,
11740
11899
  feel: 'required',
11741
11900
  getValue,
11742
11901
  id,
11743
- label: 'Hide if',
11902
+ label,
11744
11903
  setValue,
11745
11904
  variables
11746
11905
  });
@@ -12360,6 +12519,9 @@ function GeneralGroup(field, editField, getService) {
12360
12519
  }), ...NumberEntries({
12361
12520
  field,
12362
12521
  editField
12522
+ }), ...ExpressionFieldEntries({
12523
+ field,
12524
+ editField
12363
12525
  }), ...ImageSourceEntry({
12364
12526
  field,
12365
12527
  editField