@bpmn-io/form-js-editor 1.10.1 → 1.11.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
@@ -1516,6 +1516,8 @@ function Palette(props) {
1516
1516
  const initialPaletteEntries = hooks.useRef(collectPaletteEntries(formFields));
1517
1517
  const [paletteEntries, setPaletteEntries] = hooks.useState(initialPaletteEntries.current);
1518
1518
  const [searchTerm, setSearchTerm] = hooks.useState('');
1519
+
1520
+ /** @type {import("preact").RefObject<HTMLInputElement>} */
1519
1521
  const inputRef = hooks.useRef();
1520
1522
  const groups = groupEntries(paletteEntries);
1521
1523
  const simplifyString = hooks.useCallback(str => {
@@ -1638,7 +1640,8 @@ function collectPaletteEntries(formFields) {
1638
1640
  config: fieldConfig
1639
1641
  } = formField;
1640
1642
  return {
1641
- label: fieldConfig.label,
1643
+ // fieldConfig.label is used to maintain backwards compatibility with custom form fields
1644
+ label: fieldConfig.name || fieldConfig.label,
1642
1645
  type: type,
1643
1646
  group: fieldConfig.group,
1644
1647
  icon: fieldConfig.icon,
@@ -1941,6 +1944,29 @@ class Dragging {
1941
1944
  }
1942
1945
  return !target.classList.contains(DRAG_NO_DROP_CLS);
1943
1946
  },
1947
+ transformOffset: (offset, event, element) => {
1948
+ if (element.classList.contains(DRAG_ROW_MOVE_CLS)) {
1949
+ const rowOffset = {
1950
+ x: -5,
1951
+ y: -60
1952
+ };
1953
+ return {
1954
+ left: event.clientX + rowOffset.x,
1955
+ top: event.clientY + rowOffset.y
1956
+ };
1957
+ }
1958
+ if (element.classList.contains(DRAG_MOVE_CLS)) {
1959
+ const iconOffset = {
1960
+ x: -5,
1961
+ y: -15
1962
+ };
1963
+ return {
1964
+ left: event.clientX + iconOffset.x,
1965
+ top: event.clientY + iconOffset.y
1966
+ };
1967
+ }
1968
+ return offset;
1969
+ },
1944
1970
  slideFactorX: 10,
1945
1971
  slideFactorY: 5
1946
1972
  };
@@ -2236,6 +2262,8 @@ function Element$1(props) {
2236
2262
  type,
2237
2263
  showOutline
2238
2264
  } = field;
2265
+
2266
+ /** @type {import("preact").RefObject<HTMLDivElement>} */
2239
2267
  const ref = hooks.useRef();
2240
2268
  const [hovered, setHovered] = hooks.useState(false);
2241
2269
  hooks.useEffect(() => {
@@ -7244,12 +7272,13 @@ function FeelTextfieldComponent(props) {
7244
7272
  setFocus(-1);
7245
7273
  }
7246
7274
  };
7247
- const handleLint = useStaticCallback(lint => {
7248
- if (!(lint && lint.length)) {
7275
+ const handleLint = useStaticCallback((lint = []) => {
7276
+ const syntaxError = lint.some(report => report.type === 'Syntax Error');
7277
+ if (syntaxError) {
7278
+ onError('Unparsable FEEL expression.');
7279
+ } else {
7249
7280
  onError(undefined);
7250
- return;
7251
7281
  }
7252
- onError('Unparsable FEEL expression.');
7253
7282
  });
7254
7283
  const handlePopupOpen = (type = 'feel') => {
7255
7284
  const popupOptions = {
@@ -8981,82 +9010,6 @@ const FormPropertiesPanelContext = preact.createContext({
8981
9010
  getService
8982
9011
  });
8983
9012
 
8984
- function arrayAdd(array, index, item) {
8985
- const copy = [...array];
8986
- copy.splice(index, 0, item);
8987
- return copy;
8988
- }
8989
- function countDecimals(number) {
8990
- const num = Big(number);
8991
- if (num.toString() === num.toFixed(0)) return 0;
8992
- return num.toFixed().split('.')[1].length || 0;
8993
- }
8994
-
8995
- /**
8996
- *
8997
- * @param {unknown} value
8998
- * @returns {boolean}
8999
- */
9000
- function isValidNumber(value) {
9001
- return (typeof value === 'number' || typeof value === 'string') && value !== '' && !isNaN(Number(value));
9002
- }
9003
- function textToLabel(text) {
9004
- if (typeof text != 'string') return null;
9005
- for (const line of text.split('\n')) {
9006
- const displayLine = line.trim();
9007
-
9008
- // we use the first non-whitespace line in the text as label
9009
- if (displayLine !== '') {
9010
- return displayLine;
9011
- }
9012
- }
9013
- return null;
9014
- }
9015
-
9016
- /**
9017
- * @param {string} path
9018
- */
9019
- function isValidDotPath(path) {
9020
- return /^\w+(\.\w+)*$/.test(path);
9021
- }
9022
-
9023
- /**
9024
- * @param {string} path
9025
- */
9026
- function isProhibitedPath(path) {
9027
- const prohibitedSegments = ['__proto__', 'prototype', 'constructor'];
9028
- return path.split('.').some(segment => prohibitedSegments.includes(segment));
9029
- }
9030
- const LABELED_NON_INPUTS = ['button', 'group', 'dynamiclist', 'iframe', 'table'];
9031
- const INPUTS = ['checkbox', 'checklist', 'datetime', 'number', 'radio', 'select', 'taglist', 'textfield', 'textarea'];
9032
- const OPTIONS_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
9033
- function hasEntryConfigured(formFieldDefinition, entryId) {
9034
- const {
9035
- propertiesPanelEntries = []
9036
- } = formFieldDefinition;
9037
- if (!propertiesPanelEntries.length) {
9038
- return false;
9039
- }
9040
- return propertiesPanelEntries.some(id => id === entryId);
9041
- }
9042
- function hasOptionsGroupsConfigured(formFieldDefinition) {
9043
- const {
9044
- propertiesPanelEntries = []
9045
- } = formFieldDefinition;
9046
- if (!propertiesPanelEntries.length) {
9047
- return false;
9048
- }
9049
- return propertiesPanelEntries.some(id => id === 'values');
9050
- }
9051
-
9052
- /**
9053
- * @param {string} path
9054
- */
9055
- function hasIntegerPathSegment(path) {
9056
- return path.split('.').some(segment => /^\d+$/.test(segment));
9057
- }
9058
-
9059
- const headerlessTypes = ['spacer', 'separator', 'expression', 'html'];
9060
9013
  function getPropertiesPanelHeaderProvider(options = {}) {
9061
9014
  const {
9062
9015
  getDocumentationRef,
@@ -9067,19 +9020,8 @@ function getPropertiesPanelHeaderProvider(options = {}) {
9067
9020
  const {
9068
9021
  type
9069
9022
  } = field;
9070
- if (headerlessTypes.includes(type)) {
9071
- return '';
9072
- }
9073
- if (type === 'text') {
9074
- return textToLabel(field.text);
9075
- }
9076
- if (type === 'image') {
9077
- return field.alt;
9078
- }
9079
- if (type === 'default') {
9080
- return field.id;
9081
- }
9082
- return field.label;
9023
+ const fieldDefinition = formFields.get(type).config;
9024
+ return fieldDefinition.getSubheading ? fieldDefinition.getSubheading(field) : field.label;
9083
9025
  },
9084
9026
  getElementIcon: field => {
9085
9027
  const {
@@ -9108,7 +9050,7 @@ function getPropertiesPanelHeaderProvider(options = {}) {
9108
9050
  return 'Form';
9109
9051
  }
9110
9052
  const fieldDefinition = formFields.get(type).config;
9111
- return fieldDefinition.label || type;
9053
+ return fieldDefinition.name || fieldDefinition.label || type;
9112
9054
  },
9113
9055
  getDocumentationRef
9114
9056
  };
@@ -9509,6 +9451,69 @@ function asArray(length) {
9509
9451
  }).map((_, i) => i + 1);
9510
9452
  }
9511
9453
 
9454
+ function arrayAdd(array, index, item) {
9455
+ const copy = [...array];
9456
+ copy.splice(index, 0, item);
9457
+ return copy;
9458
+ }
9459
+ function countDecimals(number) {
9460
+ const num = Big(number);
9461
+ if (num.toString() === num.toFixed(0)) return 0;
9462
+ return num.toFixed().split('.')[1].length || 0;
9463
+ }
9464
+
9465
+ /**
9466
+ *
9467
+ * @param {unknown} value
9468
+ * @returns {boolean}
9469
+ */
9470
+ function isValidNumber(value) {
9471
+ return (typeof value === 'number' || typeof value === 'string') && value !== '' && !isNaN(Number(value));
9472
+ }
9473
+
9474
+ /**
9475
+ * @param {string} path
9476
+ */
9477
+ function isValidDotPath(path) {
9478
+ return /^\w+(\.\w+)*$/.test(path);
9479
+ }
9480
+
9481
+ /**
9482
+ * @param {string} path
9483
+ */
9484
+ function isProhibitedPath(path) {
9485
+ const prohibitedSegments = ['__proto__', 'prototype', 'constructor'];
9486
+ return path.split('.').some(segment => prohibitedSegments.includes(segment));
9487
+ }
9488
+ const LABELED_NON_INPUTS = ['button', 'group', 'dynamiclist', 'iframe', 'table'];
9489
+ const INPUTS = ['checkbox', 'checklist', 'datetime', 'number', 'radio', 'select', 'taglist', 'textfield', 'textarea', 'filepicker'];
9490
+ const OPTIONS_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
9491
+ function hasEntryConfigured(formFieldDefinition, entryId) {
9492
+ const {
9493
+ propertiesPanelEntries = []
9494
+ } = formFieldDefinition;
9495
+ if (!propertiesPanelEntries.length) {
9496
+ return false;
9497
+ }
9498
+ return propertiesPanelEntries.some(id => id === entryId);
9499
+ }
9500
+ function hasOptionsGroupsConfigured(formFieldDefinition) {
9501
+ const {
9502
+ propertiesPanelEntries = []
9503
+ } = formFieldDefinition;
9504
+ if (!propertiesPanelEntries.length) {
9505
+ return false;
9506
+ }
9507
+ return propertiesPanelEntries.some(id => id === 'values');
9508
+ }
9509
+
9510
+ /**
9511
+ * @param {string} path
9512
+ */
9513
+ function hasIntegerPathSegment(path) {
9514
+ return path.split('.').some(segment => /^\d+$/.test(segment));
9515
+ }
9516
+
9512
9517
  function DescriptionEntry(props) {
9513
9518
  const {
9514
9519
  editField,
@@ -9521,7 +9526,7 @@ function DescriptionEntry(props) {
9521
9526
  editField: editField,
9522
9527
  field: field,
9523
9528
  isEdited: isEdited$6,
9524
- isDefaultVisible: field => INPUTS.includes(field.type)
9529
+ isDefaultVisible: field => field.type !== 'filepicker' && INPUTS.includes(field.type)
9525
9530
  });
9526
9531
  return entries;
9527
9532
  }
@@ -9554,7 +9559,7 @@ function Description(props) {
9554
9559
  });
9555
9560
  }
9556
9561
 
9557
- const EMPTY_OPTION = null;
9562
+ const EMPTY_OPTION = '';
9558
9563
  function DefaultValueEntry(props) {
9559
9564
  const {
9560
9565
  editField,
@@ -9573,26 +9578,26 @@ function DefaultValueEntry(props) {
9573
9578
  return matchers(field);
9574
9579
  };
9575
9580
  }
9576
- const defaulValueBase = {
9581
+ const defaultValueBase = {
9577
9582
  editField,
9578
9583
  field,
9579
9584
  id: 'defaultValue',
9580
9585
  label: 'Default value'
9581
9586
  };
9582
9587
  entries.push({
9583
- ...defaulValueBase,
9588
+ ...defaultValueBase,
9584
9589
  component: DefaultValueCheckbox,
9585
9590
  isEdited: isEdited$3,
9586
9591
  isDefaultVisible: isDefaultVisible(field => field.type === 'checkbox')
9587
9592
  });
9588
9593
  entries.push({
9589
- ...defaulValueBase,
9594
+ ...defaultValueBase,
9590
9595
  component: DefaultValueNumber,
9591
9596
  isEdited: isEdited,
9592
9597
  isDefaultVisible: isDefaultVisible(field => field.type === 'number')
9593
9598
  });
9594
9599
  entries.push({
9595
- ...defaulValueBase,
9600
+ ...defaultValueBase,
9596
9601
  component: DefaultValueSingleSelect,
9597
9602
  isEdited: isEdited$3,
9598
9603
  isDefaultVisible: isDefaultVisible(field => field.type === 'radio' || field.type === 'select')
@@ -9601,13 +9606,13 @@ function DefaultValueEntry(props) {
9601
9606
  // todo(Skaiir): implement a multiselect equivalent (cf. https://github.com/bpmn-io/form-js/issues/265)
9602
9607
 
9603
9608
  entries.push({
9604
- ...defaulValueBase,
9609
+ ...defaultValueBase,
9605
9610
  component: DefaultValueTextfield,
9606
9611
  isEdited: isEdited,
9607
9612
  isDefaultVisible: isDefaultVisible(field => field.type === 'textfield')
9608
9613
  });
9609
9614
  entries.push({
9610
- ...defaulValueBase,
9615
+ ...defaultValueBase,
9611
9616
  component: DefaultValueTextarea,
9612
9617
  isEdited: isEdited$1,
9613
9618
  isDefaultVisible: isDefaultVisible(field => field.type === 'textarea')
@@ -10689,7 +10694,7 @@ function Text(props) {
10689
10694
  };
10690
10695
  return FeelTemplatingEntry({
10691
10696
  debounce,
10692
- description: description$1,
10697
+ description: description$2,
10693
10698
  element: field,
10694
10699
  getValue,
10695
10700
  id,
@@ -10699,7 +10704,7 @@ function Text(props) {
10699
10704
  variables
10700
10705
  });
10701
10706
  }
10702
- const description$1 = jsxRuntime.jsxs(jsxRuntime.Fragment, {
10707
+ const description$2 = jsxRuntime.jsxs(jsxRuntime.Fragment, {
10703
10708
  children: ["Supports markdown and templating.", ' ', jsxRuntime.jsx("a", {
10704
10709
  href: "https://docs.camunda.io/docs/components/modeler/forms/form-element-library/forms-element-library-text/",
10705
10710
  target: "_blank",
@@ -10741,7 +10746,7 @@ function Content(props) {
10741
10746
  };
10742
10747
  return FeelTemplatingEntry({
10743
10748
  debounce,
10744
- description,
10749
+ description: description$1,
10745
10750
  element: field,
10746
10751
  getValue,
10747
10752
  id,
@@ -10755,7 +10760,7 @@ function Content(props) {
10755
10760
 
10756
10761
  // helpers //////////
10757
10762
 
10758
- const description = jsxRuntime.jsxs(jsxRuntime.Fragment, {
10763
+ const description$1 = jsxRuntime.jsxs(jsxRuntime.Fragment, {
10759
10764
  children: ["Supports HTML, styling, and templating. Styles are automatically scoped to the HTML component.", ' ', jsxRuntime.jsx("a", {
10760
10765
  href: "https://docs.camunda.io/docs/components/modeler/forms/form-element-library/forms-element-library-html/",
10761
10766
  target: "_blank",
@@ -12571,6 +12576,108 @@ function VersionTag(props) {
12571
12576
  });
12572
12577
  }
12573
12578
 
12579
+ function AcceptEntry(props) {
12580
+ const {
12581
+ editField,
12582
+ field
12583
+ } = props;
12584
+ const entries = [];
12585
+ entries.push({
12586
+ id: 'accept',
12587
+ component: Accept,
12588
+ editField: editField,
12589
+ field: field,
12590
+ isEdited: isEdited$6,
12591
+ isDefaultVisible: field => field.type === 'filepicker'
12592
+ });
12593
+ return entries;
12594
+ }
12595
+ function Accept(props) {
12596
+ const {
12597
+ editField,
12598
+ field,
12599
+ id
12600
+ } = props;
12601
+ const debounce = useService('debounce');
12602
+ const variables = useVariables().map(name => ({
12603
+ name
12604
+ }));
12605
+ const path = ['accept'];
12606
+ const getValue = () => {
12607
+ return minDash.get(field, path, '');
12608
+ };
12609
+ const setValue = value => {
12610
+ return editField(field, path, value);
12611
+ };
12612
+ return FeelTemplatingEntry({
12613
+ debounce,
12614
+ element: field,
12615
+ getValue,
12616
+ id,
12617
+ label: 'Supported file formats',
12618
+ singleLine: true,
12619
+ setValue,
12620
+ variables,
12621
+ description
12622
+ });
12623
+ }
12624
+
12625
+ // helpers //////////
12626
+
12627
+ const description = jsxRuntime.jsxs(jsxRuntime.Fragment, {
12628
+ children: ["A comma-separated list of", ' ', jsxRuntime.jsx("a", {
12629
+ href: "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers",
12630
+ target: "_blank",
12631
+ children: "file type specifiers"
12632
+ })]
12633
+ });
12634
+
12635
+ function MultipleEntry(props) {
12636
+ const {
12637
+ editField,
12638
+ field
12639
+ } = props;
12640
+ const entries = [];
12641
+ entries.push({
12642
+ id: 'multiple',
12643
+ component: Multiple,
12644
+ editField: editField,
12645
+ field: field,
12646
+ isEdited: isEdited$6,
12647
+ isDefaultVisible: field => field.type === 'filepicker'
12648
+ });
12649
+ return entries;
12650
+ }
12651
+ function Multiple(props) {
12652
+ const {
12653
+ editField,
12654
+ field,
12655
+ id
12656
+ } = props;
12657
+ const debounce = useService('debounce');
12658
+ const variables = useVariables().map(name => ({
12659
+ name
12660
+ }));
12661
+ const path = ['multiple'];
12662
+ const getValue = () => {
12663
+ return minDash.get(field, path, '');
12664
+ };
12665
+ const setValue = value => {
12666
+ return editField(field, path, value);
12667
+ };
12668
+ return FeelToggleSwitchEntry({
12669
+ debounce,
12670
+ element: field,
12671
+ feel: 'optional',
12672
+ getValue,
12673
+ id,
12674
+ label: 'Upload multiple files',
12675
+ inline: true,
12676
+ setValue,
12677
+ variables
12678
+ });
12679
+ }
12680
+
12574
12681
  function GeneralGroup(field, editField, getService) {
12575
12682
  const entries = [...IdEntry({
12576
12683
  field,
@@ -12637,6 +12744,12 @@ function GeneralGroup(field, editField, getService) {
12637
12744
  }), ...SelectEntries({
12638
12745
  field,
12639
12746
  editField
12747
+ }), ...AcceptEntry({
12748
+ field,
12749
+ editField
12750
+ }), ...MultipleEntry({
12751
+ field,
12752
+ editField
12640
12753
  }), ...DisabledEntry({
12641
12754
  field,
12642
12755
  editField