@bpmn-io/form-js-viewer 1.13.1 → 1.14.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
@@ -1118,9 +1118,6 @@ function _isElementScrollable(el) {
1118
1118
  return (overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight;
1119
1119
  }
1120
1120
 
1121
- const EMPTY_OBJECT = {};
1122
- const EMPTY_ARRAY$2 = [];
1123
-
1124
1121
  /**
1125
1122
  * Custom hook to scroll an element within a scrollable container.
1126
1123
  *
@@ -1134,8 +1131,8 @@ const EMPTY_ARRAY$2 = [];
1134
1131
  * @param {Array} [flagRefs] - An array of refs that are used as flags to control when to scroll.
1135
1132
  */
1136
1133
  function useScrollIntoView(scrolledElementRef, deps, scrollOptions, flagRefs) {
1137
- const _scrollOptions = scrollOptions || EMPTY_OBJECT;
1138
- const _flagRefs = flagRefs || EMPTY_ARRAY$2;
1134
+ const _scrollOptions = scrollOptions;
1135
+ const _flagRefs = flagRefs;
1139
1136
  useEffect(() => {
1140
1137
  // return early if flags are not raised, or component is not mounted
1141
1138
  if (some(_flagRefs, ref => !ref.current) || !scrolledElementRef.current) {
@@ -1523,9 +1520,8 @@ function _getZeroPaddedString(time) {
1523
1520
  return time.toString().padStart(2, '0');
1524
1521
  }
1525
1522
 
1526
- const ALLOWED_IMAGE_SRC_PATTERN = /^(https?|data):.*/i; // eslint-disable-line no-useless-escape
1527
- const ALLOWED_IFRAME_SRC_PATTERN = /^(https):\/\/*/i; // eslint-disable-line no-useless-escape
1528
-
1523
+ const ALLOWED_IMAGE_SRC_PATTERN = /^(https?|data):.*/i;
1524
+ const ALLOWED_IFRAME_SRC_PATTERN = /^(https):\/\/*/i;
1529
1525
  function sanitizeDateTimePickerValue(options) {
1530
1526
  const {
1531
1527
  formField,
@@ -1767,10 +1763,10 @@ function Errors(props) {
1767
1763
  "aria-live": "polite",
1768
1764
  id: id,
1769
1765
  children: jsx("ul", {
1770
- children: errors.map(error => {
1766
+ children: errors.map((error, index) => {
1771
1767
  return jsx("li", {
1772
1768
  children: error
1773
- });
1769
+ }, index);
1774
1770
  })
1775
1771
  })
1776
1772
  });
@@ -1789,7 +1785,7 @@ function Label(props) {
1789
1785
  });
1790
1786
  return jsxs("label", {
1791
1787
  id: id,
1792
- for: htmlFor,
1788
+ htmlFor: htmlFor,
1793
1789
  class: classNames('fjs-form-field-label', {
1794
1790
  'fjs-incollapsible-label': !collapseOnEmpty
1795
1791
  }, props['class']),
@@ -2272,7 +2268,7 @@ function RowsRenderer(props) {
2272
2268
  indexes: indexes
2273
2269
  });
2274
2270
  })
2275
- });
2271
+ }, row.id);
2276
2272
  }), ' ']
2277
2273
  });
2278
2274
  }
@@ -2682,16 +2678,16 @@ function DropdownList(props) {
2682
2678
  maxHeight: height,
2683
2679
  scrollBehavior: smoothScrolling ? 'smooth' : 'auto'
2684
2680
  },
2685
- children: [values.length > 0 && values.map((v, i) => {
2681
+ children: [values.length > 0 && values.map((entry, index) => {
2686
2682
  return jsx("div", {
2687
2683
  class: classNames('fjs-dropdownlist-item', {
2688
- focused: focusedValueIndex === i
2684
+ focused: focusedValueIndex === index
2689
2685
  }),
2690
- onMouseMove: mouseControl ? undefined : e => onMouseMovedInKeyboardMode(e, i),
2691
- onMouseEnter: mouseControl ? () => setFocusedValueIndex(i) : undefined,
2692
- onMouseDown: e => onValueSelected(v),
2693
- children: getLabel(v)
2694
- });
2686
+ onMouseMove: mouseControl ? undefined : e => onMouseMovedInKeyboardMode(e, index),
2687
+ onMouseEnter: mouseControl ? () => setFocusedValueIndex(index) : undefined,
2688
+ onMouseDown: e => onValueSelected(entry),
2689
+ children: getLabel(entry)
2690
+ }, entry.value);
2695
2691
  }), !values.length && jsx("div", {
2696
2692
  class: "fjs-dropdownlist-empty",
2697
2693
  children: emptyListMessage
@@ -4758,7 +4754,7 @@ function Taglist(props) {
4758
4754
  }),
4759
4755
  children: [loadState === LOAD_STATES.LOADED && jsx("div", {
4760
4756
  class: "fjs-taglist-tags",
4761
- children: values.map(v => {
4757
+ children: values.map(entry => {
4762
4758
  return jsxs("div", {
4763
4759
  class: classNames('fjs-taglist-tag', {
4764
4760
  'fjs-disabled': disabled,
@@ -4767,17 +4763,17 @@ function Taglist(props) {
4767
4763
  onMouseDown: e => e.preventDefault(),
4768
4764
  children: [jsx("span", {
4769
4765
  class: "fjs-taglist-tag-label",
4770
- children: getLabelCorrelation(v)
4766
+ children: getLabelCorrelation(entry)
4771
4767
  }), !disabled && !readonly && jsx("button", {
4772
4768
  type: "button",
4773
4769
  title: "Remove tag",
4774
4770
  class: "fjs-taglist-tag-remove",
4775
4771
  onFocus: onElementFocus,
4776
4772
  onBlur: onElementBlur,
4777
- onClick: event => onTagRemoveClick(event, v),
4773
+ onClick: event => onTagRemoveClick(event, entry),
4778
4774
  children: jsx(SvgXMark, {})
4779
4775
  })]
4780
- });
4776
+ }, entry);
4781
4777
  })
4782
4778
  }), jsx("input", {
4783
4779
  disabled: disabled,
@@ -5287,7 +5283,7 @@ function Textarea(props) {
5287
5283
  }), jsx("textarea", {
5288
5284
  class: "fjs-textarea",
5289
5285
  disabled: disabled,
5290
- readonly: readonly,
5286
+ readOnly: readonly,
5291
5287
  id: domId,
5292
5288
  onInput: onInputChange,
5293
5289
  onBlur: onInputBlur,
@@ -5434,7 +5430,7 @@ function Table(props) {
5434
5430
  key
5435
5431
  }) => key);
5436
5432
  const evaluatedDataSource = useExpressionEvaluation(dataSource);
5437
- const data = Array.isArray(evaluatedDataSource) ? evaluatedDataSource.filter(i => i !== undefined) : [];
5433
+ const data = Array.isArray(evaluatedDataSource) ? evaluatedDataSource.filter(entry => !isNil(entry) || typeof entry !== 'object') : [];
5438
5434
  const sortedData = sortBy === null ? data : sortByColumn(data, sortBy.key, sortBy.direction);
5439
5435
 
5440
5436
  /** @type {unknown[][]} */
@@ -5444,12 +5440,6 @@ function Table(props) {
5444
5440
  useEffect(() => {
5445
5441
  setCurrentPage(0);
5446
5442
  }, [rowCount, sortBy]);
5447
- const serializeCellData = cellData => {
5448
- if (cellData !== null && typeof cellData === 'object') {
5449
- return JSON.stringify(cellData);
5450
- }
5451
- return cellData;
5452
- };
5453
5443
 
5454
5444
  /** @param {string} key */
5455
5445
  function toggleSortBy(key) {
@@ -5720,6 +5710,17 @@ function getHeaderAriaLabel(sortBy, key, label) {
5720
5710
  return `Click to sort by ${label} ascending`;
5721
5711
  }
5722
5712
 
5713
+ /**
5714
+ * @param {unknown} cellData
5715
+ * @returns string
5716
+ */
5717
+ function serializeCellData(cellData) {
5718
+ if (cellData !== null && typeof cellData === 'object') {
5719
+ return JSON.stringify(cellData);
5720
+ }
5721
+ return `${cellData || ''}`;
5722
+ }
5723
+
5723
5724
  const FILE_PICKER_FILE_KEY_PREFIX = 'files::';
5724
5725
 
5725
5726
  const type$1 = 'filepicker';
@@ -5739,6 +5740,8 @@ const EMPTY_ARRAY$1 = [];
5739
5740
  * @property {string} [field.label]
5740
5741
  * @property {string} [field.accept]
5741
5742
  * @property {string|boolean} [field.multiple]
5743
+ * @property {Object} [field.validate]
5744
+ * @property {boolean} [field.validate.required]
5742
5745
  * @property {string} [value]
5743
5746
  *
5744
5747
  * @param {Props} props
@@ -5756,13 +5759,13 @@ function FilePicker(props) {
5756
5759
  errors = [],
5757
5760
  disabled,
5758
5761
  readonly,
5759
- required,
5760
5762
  value: filesKey = ''
5761
5763
  } = props;
5762
5764
  const {
5763
5765
  label,
5764
5766
  multiple = false,
5765
- accept = ''
5767
+ accept = '',
5768
+ validate = {}
5766
5769
  } = field;
5767
5770
  /** @type {string} */
5768
5771
  const evaluatedAccept = useSingleLineTemplateEvaluation(accept, {
@@ -5818,7 +5821,7 @@ function FilePicker(props) {
5818
5821
  children: [jsx(Label, {
5819
5822
  htmlFor: domId,
5820
5823
  label: label,
5821
- required: required
5824
+ required: validate.required
5822
5825
  }), jsx("input", {
5823
5826
  type: "file",
5824
5827
  className: "fjs-hidden",
@@ -5828,13 +5831,14 @@ function FilePicker(props) {
5828
5831
  disabled: isInputDisabled,
5829
5832
  multiple: evaluatedMultiple || undefined,
5830
5833
  accept: evaluatedAccept || undefined,
5831
- onChange: onFileChange
5834
+ onChange: onFileChange,
5835
+ required: validate.required
5832
5836
  }), jsxs("div", {
5833
5837
  className: "fjs-filepicker-container",
5834
5838
  children: [jsx("button", {
5835
5839
  type: "button",
5836
5840
  disabled: isInputDisabled,
5837
- readonly: readonly,
5841
+ readOnly: readonly,
5838
5842
  className: "fjs-button fjs-filepicker-button",
5839
5843
  onClick: () => {
5840
5844
  fileInputRef.current.click();
@@ -5900,6 +5904,7 @@ const type = 'documentPreview';
5900
5904
  /**
5901
5905
  * @typedef DocumentMetadata
5902
5906
  * @property {string} documentId
5907
+ * @property {string} contentHash
5903
5908
  * @property {Object} metadata
5904
5909
  * @property {string|undefined} [metadata.contentType]
5905
5910
  * @property {string} metadata.fileName
@@ -6021,7 +6026,7 @@ function isValidDocumentEndpoint(endpoint) {
6021
6026
  * @returns {metadata is DocumentMetadata}
6022
6027
  */
6023
6028
  function isValidDocument(document) {
6024
- return typeof document === 'object' && 'documentId' in document && 'metadata' in document && typeof document.metadata === 'object' && 'fileName' in document.metadata;
6029
+ return typeof document === 'object' && document !== null && 'documentId' in document && 'metadata' in document && typeof document.metadata === 'object' && 'fileName' in document.metadata;
6025
6030
  }
6026
6031
 
6027
6032
  /**
@@ -6059,7 +6064,11 @@ function DocumentRenderer(props) {
6059
6064
  const [hasError, setHasError] = useState(false);
6060
6065
  const ref = useRef(null);
6061
6066
  const isInViewport = useInViewport(ref);
6062
- const fullUrl = endpoint.replace(DOCUMENT_ID_PLACEHOLDER, documentMetadata.documentId);
6067
+ const fullUrl = buildUrl({
6068
+ baseUrl: endpoint,
6069
+ documentId: documentMetadata.documentId,
6070
+ contentHash: documentMetadata.contentHash
6071
+ });
6063
6072
  const singleDocumentContainerClassName = `fjs-${type}-single-document-container`;
6064
6073
  const errorMessageId = `${domId}-error-message`;
6065
6074
  const errorMessage = 'Unable to download document';
@@ -6169,12 +6178,16 @@ function DownloadButton(props) {
6169
6178
 
6170
6179
  /**
6171
6180
  *
6172
- * @param {import("preact").RefObject<HTMLElement>} ref
6181
+ * @param {import("preact").RefObject<HTMLElement|null>} ref
6173
6182
  * @returns boolean
6174
6183
  */
6175
6184
  function useInViewport(ref) {
6176
6185
  const [isInViewport, setIsInViewport] = useState(false);
6177
6186
  useEffect(() => {
6187
+ const container = ref.current;
6188
+ if (!container) {
6189
+ return;
6190
+ }
6178
6191
  const observer = new IntersectionObserver(([entry]) => {
6179
6192
  if (entry.isIntersecting) {
6180
6193
  setIsInViewport(true);
@@ -6182,18 +6195,39 @@ function useInViewport(ref) {
6182
6195
  }, {
6183
6196
  threshold: 0
6184
6197
  });
6185
- if (ref.current) {
6186
- observer.observe(ref.current);
6187
- }
6198
+ observer.observe(container);
6188
6199
  return () => {
6189
- if (ref.current) {
6190
- observer.unobserve(ref.current);
6200
+ if (container) {
6201
+ observer.unobserve(container);
6191
6202
  }
6192
6203
  };
6193
6204
  }, [ref]);
6194
6205
  return isInViewport;
6195
6206
  }
6196
6207
 
6208
+ /**
6209
+ * This solution should be a temporary fix, we should try to remove it via: https://github.com/bpmn-io/form-js/issues/1341
6210
+ *
6211
+ * @param {Object} options
6212
+ * @param {string} options.baseUrl
6213
+ * @param {string} options.documentId
6214
+ * @param {string} [options.contentHash]
6215
+ *
6216
+ * @returns {string}
6217
+ */
6218
+ function buildUrl(options) {
6219
+ const {
6220
+ baseUrl,
6221
+ documentId,
6222
+ contentHash
6223
+ } = options;
6224
+ const finalUrl = new URL(baseUrl.replace(DOCUMENT_ID_PLACEHOLDER, documentId));
6225
+ if (contentHash !== undefined) {
6226
+ finalUrl.searchParams.set('contentHash', contentHash);
6227
+ }
6228
+ return decodeURI(finalUrl.toString());
6229
+ }
6230
+
6197
6231
  /**
6198
6232
  * This file must not be changed or exchanged.
6199
6233
  *
@@ -6235,14 +6269,14 @@ function Lightbox(props) {
6235
6269
  children: [jsx("a", {
6236
6270
  href: "https://bpmn.io",
6237
6271
  target: "_blank",
6238
- rel: "noopener",
6272
+ rel: "noopener noreferrer",
6239
6273
  style: "margin: 15px 20px 15px 10px; align-self: center; color: var(--cds-icon-primary, #404040)",
6240
6274
  children: jsx(Logo, {})
6241
6275
  }), jsxs("span", {
6242
6276
  children: ["Web-based tooling for BPMN, DMN, and forms powered by", ' ', jsx("a", {
6243
6277
  href: "https://bpmn.io",
6244
6278
  target: "_blank",
6245
- rel: "noopener",
6279
+ rel: "noopener noreferrer",
6246
6280
  children: "bpmn.io"
6247
6281
  }), "."]
6248
6282
  })]
@@ -6256,7 +6290,7 @@ function Link(props) {
6256
6290
  children: jsx("a", {
6257
6291
  href: "https://bpmn.io",
6258
6292
  target: "_blank",
6259
- rel: "noopener",
6293
+ rel: "noopener noreferrer",
6260
6294
  class: "fjs-powered-by-link",
6261
6295
  title: "Powered by bpmn.io",
6262
6296
  style: "color: var(--cds-text-primary, #404040)",
@@ -7461,7 +7495,7 @@ class RepeatRenderManager {
7461
7495
  showRemove: showRemove,
7462
7496
  ...restProps
7463
7497
  })
7464
- }))
7498
+ }, itemIndex))
7465
7499
  });
7466
7500
  }
7467
7501
  RepeatFooter(props) {