@bpmn-io/form-js-editor 1.12.0 → 1.13.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,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, 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';
2
+ import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Label as Label$3, IFrame, Text as Text$1, Html, Table, ExpressionField, DocumentPreview, 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, set as set$1, reduce, without, isNil, has } from 'min-dash';
5
5
  import classnames from 'classnames';
@@ -1182,7 +1182,37 @@ EditorExpressionField.config = {
1182
1182
  escapeGridRender: false
1183
1183
  };
1184
1184
 
1185
- const editorFormFields = [EditorIFrame, EditorText, EditorHtml, EditorTable, EditorExpressionField];
1185
+ function EditorDocumentPreview(props) {
1186
+ const {
1187
+ field,
1188
+ domId
1189
+ } = props;
1190
+ const {
1191
+ label
1192
+ } = field;
1193
+ const Icon = iconsByType(field.type);
1194
+ return jsxs("div", {
1195
+ class: editorFormFieldClasses(field.type),
1196
+ children: [jsx(Label$3, {
1197
+ id: domId,
1198
+ label: label
1199
+ }), jsx("div", {
1200
+ class: "fjs-documentPreview-placeholder",
1201
+ id: domId,
1202
+ children: jsxs("p", {
1203
+ class: "fjs-documentPreview-placeholder-text",
1204
+ children: [jsx(Icon, {
1205
+ width: "32",
1206
+ height: "24",
1207
+ viewBox: "0 0 56 56"
1208
+ }), "Document preview"]
1209
+ })
1210
+ })]
1211
+ });
1212
+ }
1213
+ EditorDocumentPreview.config = DocumentPreview.config;
1214
+
1215
+ const editorFormFields = [EditorIFrame, EditorText, EditorHtml, EditorTable, EditorExpressionField, EditorDocumentPreview];
1186
1216
 
1187
1217
  class EditorFormFields extends FormFields {
1188
1218
  constructor() {
@@ -9479,7 +9509,7 @@ function isProhibitedPath(path) {
9479
9509
  const prohibitedSegments = ['__proto__', 'prototype', 'constructor'];
9480
9510
  return path.split('.').some(segment => prohibitedSegments.includes(segment));
9481
9511
  }
9482
- const LABELED_NON_INPUTS = ['button', 'group', 'dynamiclist', 'iframe', 'table'];
9512
+ const LABELED_NON_INPUTS = ['button', 'group', 'dynamiclist', 'iframe', 'table', 'documentPreview'];
9483
9513
  const INPUTS = ['checkbox', 'checklist', 'datetime', 'number', 'radio', 'select', 'taglist', 'textfield', 'textarea', 'filepicker'];
9484
9514
  const OPTIONS_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
9485
9515
  function hasEntryConfigured(formFieldDefinition, entryId) {
@@ -10326,7 +10356,7 @@ function LabelEntry(props) {
10326
10356
  return field.type === 'datetime' && (field.subtype === DATETIME_SUBTYPES.TIME || field.subtype === DATETIME_SUBTYPES.DATETIME);
10327
10357
  }
10328
10358
  });
10329
- const isSimplyLabled = field => {
10359
+ const isSimplyLabeled = field => {
10330
10360
  return [...INPUTS.filter(input => input !== 'datetime'), ...LABELED_NON_INPUTS].includes(field.type);
10331
10361
  };
10332
10362
  entries.push({
@@ -10335,7 +10365,7 @@ function LabelEntry(props) {
10335
10365
  editField,
10336
10366
  field,
10337
10367
  isEdited: isEdited$6,
10338
- isDefaultVisible: isSimplyLabled
10368
+ isDefaultVisible: isSimplyLabeled
10339
10369
  });
10340
10370
  return entries;
10341
10371
  }
@@ -10439,6 +10469,7 @@ function getLabelText(type) {
10439
10469
  case 'table':
10440
10470
  return 'Table label';
10441
10471
  case 'iframe':
10472
+ case 'documentPreview':
10442
10473
  return 'Title';
10443
10474
  default:
10444
10475
  return 'Field label';
@@ -10495,7 +10526,7 @@ function Height(props) {
10495
10526
  id,
10496
10527
  getValue,
10497
10528
  setValue,
10498
- validate: validate$7
10529
+ validate: validate$a
10499
10530
  });
10500
10531
  }
10501
10532
 
@@ -10505,7 +10536,7 @@ function Height(props) {
10505
10536
  * @param {number|void} value
10506
10537
  * @returns {string|null}
10507
10538
  */
10508
- const validate$7 = value => {
10539
+ const validate$a = value => {
10509
10540
  if (typeof value !== 'number') {
10510
10541
  return 'A number is required.';
10511
10542
  }
@@ -10570,7 +10601,7 @@ function Url(props) {
10570
10601
  setValue,
10571
10602
  singleLine: true,
10572
10603
  tooltip: getTooltip$1(),
10573
- validate: validate$6,
10604
+ validate: validate$9,
10574
10605
  variables
10575
10606
  });
10576
10607
  }
@@ -10597,7 +10628,7 @@ function getTooltip$1() {
10597
10628
  * @param {string|void} value
10598
10629
  * @returns {string|null}
10599
10630
  */
10600
- const validate$6 = value => {
10631
+ const validate$9 = value => {
10601
10632
  if (!value || value.startsWith('=')) {
10602
10633
  return;
10603
10634
  }
@@ -10688,7 +10719,7 @@ function Text(props) {
10688
10719
  };
10689
10720
  return FeelTemplatingEntry({
10690
10721
  debounce,
10691
- description: description$2,
10722
+ description: description$4,
10692
10723
  element: field,
10693
10724
  getValue,
10694
10725
  id,
@@ -10698,7 +10729,7 @@ function Text(props) {
10698
10729
  variables
10699
10730
  });
10700
10731
  }
10701
- const description$2 = jsxs(Fragment$1, {
10732
+ const description$4 = jsxs(Fragment$1, {
10702
10733
  children: ["Supports markdown and templating.", ' ', jsx("a", {
10703
10734
  href: "https://docs.camunda.io/docs/components/modeler/forms/form-element-library/forms-element-library-text/",
10704
10735
  target: "_blank",
@@ -10740,13 +10771,13 @@ function Content(props) {
10740
10771
  };
10741
10772
  return FeelTemplatingEntry({
10742
10773
  debounce,
10743
- description: description$1,
10774
+ description: description$3,
10744
10775
  element: field,
10745
10776
  getValue,
10746
10777
  id,
10747
10778
  label: 'Content',
10748
10779
  hostLanguage: 'html',
10749
- validate: validate$5,
10780
+ validate: validate$8,
10750
10781
  setValue,
10751
10782
  variables
10752
10783
  });
@@ -10754,7 +10785,7 @@ function Content(props) {
10754
10785
 
10755
10786
  // helpers //////////
10756
10787
 
10757
- const description$1 = jsxs(Fragment$1, {
10788
+ const description$3 = jsxs(Fragment$1, {
10758
10789
  children: ["Supports HTML, styling, and templating. Styles are automatically scoped to the HTML component.", ' ', jsx("a", {
10759
10790
  href: "https://docs.camunda.io/docs/components/modeler/forms/form-element-library/forms-element-library-html/",
10760
10791
  target: "_blank",
@@ -10766,7 +10797,7 @@ const description$1 = jsxs(Fragment$1, {
10766
10797
  * @param {string|void} value
10767
10798
  * @returns {string|null}
10768
10799
  */
10769
- const validate$5 = value => {
10800
+ const validate$8 = value => {
10770
10801
  // allow empty state
10771
10802
  if (typeof value !== 'string' || value === '') {
10772
10803
  return null;
@@ -11605,7 +11636,7 @@ function InputValuesKey(props) {
11605
11636
  id,
11606
11637
  label: 'Input values key',
11607
11638
  setValue,
11608
- validate: validate$4
11639
+ validate: validate$7
11609
11640
  });
11610
11641
  }
11611
11642
 
@@ -11615,7 +11646,7 @@ function InputValuesKey(props) {
11615
11646
  * @param {string|void} value
11616
11647
  * @returns {string|null}
11617
11648
  */
11618
- const validate$4 = value => {
11649
+ const validate$7 = value => {
11619
11650
  if (typeof value !== 'string' || value.length === 0) {
11620
11651
  return 'Must not be empty.';
11621
11652
  }
@@ -12058,7 +12089,7 @@ function Source(props) {
12058
12089
  setValue,
12059
12090
  singleLine: true,
12060
12091
  variables,
12061
- validate: validate$3
12092
+ validate: validate$6
12062
12093
  });
12063
12094
  }
12064
12095
 
@@ -12068,7 +12099,7 @@ function Source(props) {
12068
12099
  * @param {string|void} value
12069
12100
  * @returns {string|null}
12070
12101
  */
12071
- const validate$3 = value => {
12102
+ const validate$6 = value => {
12072
12103
  if (!isString(value) || value.length === 0) {
12073
12104
  return 'Must not be empty.';
12074
12105
  }
@@ -12172,7 +12203,7 @@ function RowCount(props) {
12172
12203
  id,
12173
12204
  getValue,
12174
12205
  setValue,
12175
- validate: validate$2
12206
+ validate: validate$5
12176
12207
  });
12177
12208
  }
12178
12209
 
@@ -12182,7 +12213,7 @@ function RowCount(props) {
12182
12213
  * @param {string|void} value
12183
12214
  * @returns {string|null}
12184
12215
  */
12185
- const validate$2 = value => {
12216
+ const validate$5 = value => {
12186
12217
  if (isNil(value)) {
12187
12218
  return null;
12188
12219
  }
@@ -12356,7 +12387,7 @@ function ColumnsExpression(props) {
12356
12387
  setValue,
12357
12388
  singleLine: true,
12358
12389
  variables,
12359
- validate: validate$1
12390
+ validate: validate$4
12360
12391
  });
12361
12392
  }
12362
12393
 
@@ -12366,7 +12397,7 @@ function ColumnsExpression(props) {
12366
12397
  * @param {string|void} value
12367
12398
  * @returns {string|null}
12368
12399
  */
12369
- const validate$1 = value => {
12400
+ const validate$4 = value => {
12370
12401
  if (!isString(value) || value.length === 0 || value === '=') {
12371
12402
  return 'Must not be empty.';
12372
12403
  }
@@ -12464,7 +12495,7 @@ function Key(props) {
12464
12495
  id,
12465
12496
  label: 'Key',
12466
12497
  setValue,
12467
- validate
12498
+ validate: validate$3
12468
12499
  });
12469
12500
  }
12470
12501
 
@@ -12474,7 +12505,7 @@ function Key(props) {
12474
12505
  * @param {string|void} value
12475
12506
  * @returns {string|null}
12476
12507
  */
12477
- function validate(value) {
12508
+ function validate$3(value) {
12478
12509
  if (!isString(value) || value.length === 0) {
12479
12510
  return 'Must not be empty.';
12480
12511
  }
@@ -12612,13 +12643,13 @@ function Accept(props) {
12612
12643
  singleLine: true,
12613
12644
  setValue,
12614
12645
  variables,
12615
- description
12646
+ description: description$2
12616
12647
  });
12617
12648
  }
12618
12649
 
12619
12650
  // helpers //////////
12620
12651
 
12621
- const description = jsxs(Fragment$1, {
12652
+ const description$2 = jsxs(Fragment$1, {
12622
12653
  children: ["A comma-separated list of", ' ', jsx("a", {
12623
12654
  href: "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers",
12624
12655
  target: "_blank",
@@ -12672,6 +12703,236 @@ function Multiple(props) {
12672
12703
  });
12673
12704
  }
12674
12705
 
12706
+ function DocumentsDataSourceEntry(props) {
12707
+ const {
12708
+ editField,
12709
+ field
12710
+ } = props;
12711
+ const entries = [];
12712
+ entries.push({
12713
+ id: 'dataSource',
12714
+ component: DocumentsDataSource,
12715
+ editField: editField,
12716
+ field: field,
12717
+ isEdited: isEdited$6,
12718
+ isDefaultVisible: field => field.type === 'documentPreview'
12719
+ });
12720
+ return entries;
12721
+ }
12722
+ function DocumentsDataSource(props) {
12723
+ const {
12724
+ editField,
12725
+ field,
12726
+ id
12727
+ } = props;
12728
+ const debounce = useService('debounce');
12729
+ const variables = useVariables().map(name => ({
12730
+ name
12731
+ }));
12732
+ const path = ['dataSource'];
12733
+ const getValue = () => {
12734
+ return get(field, path, '');
12735
+ };
12736
+ const setValue = value => {
12737
+ return editField(field, path, value);
12738
+ };
12739
+ const schema = `[
12740
+ {
12741
+ "documentId": "u123",
12742
+ "metadata": {
12743
+ "fileName": "Document.pdf",
12744
+ "contentType": "application/pdf"
12745
+ }
12746
+ }
12747
+ ]`;
12748
+ const tooltip = jsxs("div", {
12749
+ children: [jsx("p", {
12750
+ children: "A source is a JSON object containing metadata for a document or an array of documents."
12751
+ }), jsx("p", {
12752
+ children: "Each entry must include a document ID, name, and MIME type."
12753
+ }), jsx("p", {
12754
+ children: "Additional details are optional. The expected format is as follows:"
12755
+ }), jsx("pre", {
12756
+ children: jsx("code", {
12757
+ children: schema
12758
+ })
12759
+ })]
12760
+ });
12761
+ return FeelTemplatingEntry({
12762
+ debounce,
12763
+ element: field,
12764
+ getValue,
12765
+ id,
12766
+ label: 'Document reference',
12767
+ feel: 'required',
12768
+ singleLine: true,
12769
+ setValue,
12770
+ variables,
12771
+ tooltip,
12772
+ validate: validate$2
12773
+ });
12774
+ }
12775
+
12776
+ // helpers //////////
12777
+
12778
+ /**
12779
+ * @param {string|undefined} value
12780
+ * @returns {string|null}
12781
+ */
12782
+ const validate$2 = value => {
12783
+ if (typeof value !== 'string' || value.length === 0) {
12784
+ return 'The document data source is required.';
12785
+ }
12786
+ };
12787
+
12788
+ function EndpointKeyEntry(props) {
12789
+ const {
12790
+ editField,
12791
+ field
12792
+ } = props;
12793
+ const entries = [];
12794
+ entries.push({
12795
+ id: 'endpointKey',
12796
+ component: EndpointKey,
12797
+ editField: editField,
12798
+ field: field,
12799
+ isEdited: isEdited$6,
12800
+ isDefaultVisible: field => field.type === 'documentPreview'
12801
+ });
12802
+ return entries;
12803
+ }
12804
+ function EndpointKey(props) {
12805
+ const {
12806
+ editField,
12807
+ field,
12808
+ id
12809
+ } = props;
12810
+ const debounce = useService('debounce');
12811
+ const variables = useVariables().map(name => ({
12812
+ name
12813
+ }));
12814
+ const path = ['endpointKey'];
12815
+ const getValue = () => {
12816
+ return get(field, path, '');
12817
+ };
12818
+ const setValue = value => {
12819
+ return editField(field, path, value);
12820
+ };
12821
+ const tooltip = jsxs("div", {
12822
+ children: [jsx("p", {
12823
+ children: "Enter a context key that generates a string with the API endpoint to download a document."
12824
+ }), jsxs("p", {
12825
+ children: ["The string must contain ", jsx("code", {
12826
+ children: '{ documentId }'
12827
+ }), ", which will be replaced with the document ID from the document's reference."]
12828
+ }), jsx("p", {
12829
+ children: "If you're using the Camunda Tasklist, this variable is automatically added to the context for you."
12830
+ }), jsxs("p", {
12831
+ children: ["For more details, see the", ' ', jsx("a", {
12832
+ href: "https://docs.camunda.io",
12833
+ rel: "noopener noreferrer",
12834
+ target: "_blank",
12835
+ children: "Camunda documentation"
12836
+ })]
12837
+ })]
12838
+ });
12839
+ return FeelTemplatingEntry({
12840
+ debounce,
12841
+ element: field,
12842
+ getValue,
12843
+ id,
12844
+ label: 'Document URL',
12845
+ feel: 'required',
12846
+ singleLine: true,
12847
+ setValue,
12848
+ variables,
12849
+ description: description$1,
12850
+ tooltip,
12851
+ validate: validate$1
12852
+ });
12853
+ }
12854
+
12855
+ // helpers //////////
12856
+
12857
+ /**
12858
+ * @param {string|undefined} value
12859
+ * @returns {string|null}
12860
+ */
12861
+ const validate$1 = value => {
12862
+ if (typeof value !== 'string' || value.length === 0) {
12863
+ return 'The document reference is required.';
12864
+ }
12865
+ };
12866
+ const description$1 = jsx(Fragment$1, {
12867
+ children: "Define an API URL for downloading a document"
12868
+ });
12869
+
12870
+ function MaxHeightEntry(props) {
12871
+ const {
12872
+ editField,
12873
+ field
12874
+ } = props;
12875
+ const entries = [];
12876
+ entries.push({
12877
+ id: 'maxHeight',
12878
+ component: MaxHeight,
12879
+ editField: editField,
12880
+ field: field,
12881
+ isEdited: isEdited$7,
12882
+ isDefaultVisible: field => field.type === 'documentPreview'
12883
+ });
12884
+ return entries;
12885
+ }
12886
+ function MaxHeight(props) {
12887
+ const {
12888
+ editField,
12889
+ field,
12890
+ id
12891
+ } = props;
12892
+ const debounce = useService('debounce');
12893
+ const path = ['maxHeight'];
12894
+ const getValue = () => {
12895
+ return get(field, path, '');
12896
+ };
12897
+ const setValue = value => {
12898
+ return editField(field, path, value);
12899
+ };
12900
+ return NumberFieldEntry({
12901
+ debounce,
12902
+ label: 'Max height of preview container',
12903
+ element: field,
12904
+ id,
12905
+ getValue,
12906
+ setValue,
12907
+ validate,
12908
+ description
12909
+ });
12910
+ }
12911
+
12912
+ // helpers //////////
12913
+
12914
+ /**
12915
+ * @param {string|number|undefined} value
12916
+ * @returns {string|null}
12917
+ */
12918
+ const validate = value => {
12919
+ if (value === undefined || value === '') {
12920
+ return null;
12921
+ }
12922
+ if (typeof value === 'string') {
12923
+ return 'Value must be a number.';
12924
+ }
12925
+ if (!Number.isInteger(value)) {
12926
+ return 'Should be an integer.';
12927
+ }
12928
+ if (value < 1) {
12929
+ return 'Should be greater than zero.';
12930
+ }
12931
+ };
12932
+ const description = jsx(Fragment$1, {
12933
+ children: "Documents with height that exceeds the defined value will be vertically scrollable"
12934
+ });
12935
+
12675
12936
  function GeneralGroup(field, editField, getService) {
12676
12937
  const entries = [...IdEntry({
12677
12938
  field,
@@ -12759,6 +13020,9 @@ function GeneralGroup(field, editField, getService) {
12759
13020
  }), ...RowCountEntry({
12760
13021
  field,
12761
13022
  editField
13023
+ }), ...DocumentsDataSourceEntry({
13024
+ field,
13025
+ editField
12762
13026
  })];
12763
13027
  if (entries.length === 0) {
12764
13028
  return null;
@@ -13216,6 +13480,9 @@ function AppearanceGroup(field, editField, getService) {
13216
13480
  }), ...LayouterAppearanceEntry({
13217
13481
  field,
13218
13482
  editField
13483
+ }), ...MaxHeightEntry({
13484
+ field,
13485
+ editField
13219
13486
  })];
13220
13487
  if (!entries.length) {
13221
13488
  return null;
@@ -13384,6 +13651,21 @@ const TOOLTIP_TEXT = `"List of items" defines a constant, predefined set of form
13384
13651
  "Expression" defines options that are populated from a FEEL expression.
13385
13652
  `;
13386
13653
 
13654
+ function DownloadSettings(field, editField) {
13655
+ const entries = [...EndpointKeyEntry({
13656
+ field,
13657
+ editField
13658
+ })];
13659
+ if (!entries.length) {
13660
+ return null;
13661
+ }
13662
+ return {
13663
+ id: 'downloadSettings',
13664
+ label: 'Download settings',
13665
+ entries
13666
+ };
13667
+ }
13668
+
13387
13669
  class PropertiesProvider {
13388
13670
  constructor(propertiesPanel, injector) {
13389
13671
  this._injector = injector;
@@ -13419,7 +13701,7 @@ class PropertiesProvider {
13419
13701
  return groups;
13420
13702
  }
13421
13703
  const getService = (type, strict = true) => this._injector.get(type, strict);
13422
- groups = [...groups, GeneralGroup(field, editField, getService), ...OptionsGroups(field, editField, getService), ...TableHeaderGroups(field, editField), SecurityAttributesGroup(field, editField), ConditionGroup(field, editField), LayoutGroup(field, editField), AppearanceGroup(field, editField), SerializationGroup(field, editField), ConstraintsGroup(field, editField), ValidationGroup(field, editField), CustomPropertiesGroup(field, editField)].filter(group => group != null);
13704
+ groups = [...groups, GeneralGroup(field, editField, getService), DownloadSettings(field, editField), ...OptionsGroups(field, editField, getService), ...TableHeaderGroups(field, editField), SecurityAttributesGroup(field, editField), ConditionGroup(field, editField), LayoutGroup(field, editField), AppearanceGroup(field, editField), SerializationGroup(field, editField), ConstraintsGroup(field, editField), ValidationGroup(field, editField), CustomPropertiesGroup(field, editField)].filter(group => group != null);
13423
13705
  this._filterVisibleEntries(groups, field, getService);
13424
13706
 
13425
13707
  // contract: if a group has no entries or items, it should not be displayed at all