@abgov/jsonforms-components 2.79.3 → 2.79.4

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/index.esm.js CHANGED
@@ -9321,7 +9321,9 @@ class ContextProviderClass {
9321
9321
  this.enumValues.set(key, () => data);
9322
9322
  };
9323
9323
  this.setup = props => {
9324
- var _props$isFormSubmitte, _props$showChangeButt, _props$autoPopulatedD, _this$selfProps;
9324
+ var _this$selfProps, _this$selfProps2, _props$isFormSubmitte, _props$showChangeButt, _props$autoPopulatedD, _this$selfProps3;
9325
+ const previousFileManagement = (_this$selfProps = this.selfProps) == null ? void 0 : _this$selfProps.fileManagement;
9326
+ const previousData = (_this$selfProps2 = this.selfProps) == null ? void 0 : _this$selfProps2.data;
9325
9327
  this.selfProps = props;
9326
9328
  if (props.fileManagement) {
9327
9329
  const {
@@ -9370,24 +9372,27 @@ class ContextProviderClass {
9370
9372
  navigationTarget: props.navigationTarget,
9371
9373
  onNavigationChange: props.onNavigationChange
9372
9374
  });
9373
- if (HOST_CONTROLLED_KEYS.some(key => next[key] !== this.baseEnumerator[key])) {
9375
+ const hostControlledChanged = HOST_CONTROLLED_KEYS.some(key => next[key] !== this.baseEnumerator[key]);
9376
+ const fileManagementChanged = props.fileManagement !== previousFileManagement;
9377
+ const dataChanged = props.data !== previousData;
9378
+ if (hostControlledChanged || fileManagementChanged || dataChanged) {
9374
9379
  this.baseEnumerator = next;
9375
9380
  }
9376
9381
  return jsx(JsonFormContext.Provider, {
9377
9382
  value: this.baseEnumerator,
9378
- children: (_this$selfProps = this.selfProps) == null ? void 0 : _this$selfProps.children
9383
+ children: (_this$selfProps3 = this.selfProps) == null ? void 0 : _this$selfProps3.children
9379
9384
  });
9380
9385
  };
9381
9386
  this.getContextProvider = () => {
9382
- var _this$selfProps2;
9387
+ var _this$selfProps4;
9383
9388
  return jsx(JsonFormContext.Provider, {
9384
9389
  value: this.baseEnumerator,
9385
- children: (_this$selfProps2 = this.selfProps) == null ? void 0 : _this$selfProps2.children
9390
+ children: (_this$selfProps4 = this.selfProps) == null ? void 0 : _this$selfProps4.children
9386
9391
  });
9387
9392
  };
9388
9393
  this.getFormUrl = () => {
9389
- var _this$selfProps3;
9390
- return (_this$selfProps3 = this.selfProps) == null ? void 0 : _this$selfProps3.formUrl;
9394
+ var _this$selfProps5;
9395
+ return (_this$selfProps5 = this.selfProps) == null ? void 0 : _this$selfProps5.formUrl;
9391
9396
  };
9392
9397
  this.getAxiosInterceptorConfig = axios => {
9393
9398
  const requestId = axios.interceptors.request.use(req => {
@@ -16172,6 +16177,366 @@ const ObjectArrayControl = props => {
16172
16177
  return content;
16173
16178
  };
16174
16179
 
16180
+ let _$1 = t => t,
16181
+ _t$2;
16182
+ const GoAContextMenuIcon = props => {
16183
+ return jsx(GoabIconButton, {
16184
+ icon: props.type,
16185
+ onClick: props.onClick,
16186
+ title: props.title,
16187
+ testId: props.testId,
16188
+ size: "small",
16189
+ disabled: props.disabled
16190
+ });
16191
+ };
16192
+ const GoAContextMenu = styled.div(_t$2 || (_t$2 = _$1`
16193
+ display: flex;
16194
+ align-items: center;
16195
+ background-color: #fff;
16196
+ gap: var(--goa-space-2xs);
16197
+
16198
+ > .goa-icon-button {
16199
+ cursor: pointer;
16200
+ border-radius: var(--goa-border-radius-m);
16201
+ padding: var(--goa-space-2xs);
16202
+ }
16203
+ > .goa-icon-button + .goa-icon-button {
16204
+ margin-left: var(--goa-space-none);
16205
+ }
16206
+ `));
16207
+
16208
+ const DeleteFileModal = ({
16209
+ isOpen,
16210
+ title,
16211
+ content,
16212
+ onDelete,
16213
+ onCancel
16214
+ }) => {
16215
+ return jsx(GoabModal, {
16216
+ testId: "delete-confirmation",
16217
+ open: isOpen,
16218
+ heading: title,
16219
+ maxWidth: "640px",
16220
+ actions: jsxs(GoabButtonGroup, {
16221
+ alignment: "end",
16222
+ children: [jsx(GoabButton, {
16223
+ type: "secondary",
16224
+ testId: "delete-cancel",
16225
+ onClick: onCancel,
16226
+ children: "Cancel"
16227
+ }), jsx(GoabButton, {
16228
+ type: "primary",
16229
+ variant: "destructive",
16230
+ testId: "delete-confirm",
16231
+ onClick: onDelete,
16232
+ children: "Delete"
16233
+ })]
16234
+ }),
16235
+ children: content
16236
+ });
16237
+ };
16238
+
16239
+ let _2 = t => t,
16240
+ _t$1,
16241
+ _t2$1,
16242
+ _t3,
16243
+ _t4;
16244
+ const _excluded$3 = ["data", "path", "handleChange", "uischema"];
16245
+ const FileUploaderReview = props => {
16246
+ return FileUploader(Object.assign({}, props, {
16247
+ isStepperReview: true
16248
+ }));
16249
+ };
16250
+ const FileUploader = _ref => {
16251
+ var _enumerators$function, _enumerators$function2, _enumerators$function3, _uischema$options, _uischema$options2, _uischema$options3, _uischema$options4, _props$schema, _uischema$options$com, _uischema$options5, _uischema$options6, _uischema$options$com2, _uischema$options7, _uischema$options$com3, _uischema$options8, _uischema$options9;
16252
+ let {
16253
+ data,
16254
+ path,
16255
+ handleChange,
16256
+ uischema
16257
+ } = _ref,
16258
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$3);
16259
+ const enumerators = useContext(JsonFormContext);
16260
+ const uploadTriggerFunction = enumerators == null || (_enumerators$function = enumerators.functions) == null ? void 0 : _enumerators$function.get('upload-file');
16261
+ const uploadTrigger = uploadTriggerFunction && uploadTriggerFunction();
16262
+ const downloadTriggerFunction = enumerators == null || (_enumerators$function2 = enumerators.functions) == null ? void 0 : _enumerators$function2.get('download-file');
16263
+ const downloadTrigger = downloadTriggerFunction && downloadTriggerFunction();
16264
+ const deleteTriggerFunction = enumerators == null || (_enumerators$function3 = enumerators.functions) == null ? void 0 : _enumerators$function3.get('delete-file');
16265
+ const deleteTrigger = deleteTriggerFunction && deleteTriggerFunction();
16266
+ const fileListValue = enumerators == null ? void 0 : enumerators.data.get('file-list');
16267
+ const [loadingFileName, setLoadingFileName] = useState(undefined);
16268
+ const [uploadError, setUploadError] = useState(undefined);
16269
+ const countries = ['Argentina', 'Brazil', 'Canada', 'Denmark', 'Egypt', 'France', 'Greece', 'India', 'Japan', 'Kenya'];
16270
+ enumerators == null || enumerators.addFormContextData('countries', countries);
16271
+ const user = enumerators == null ? void 0 : enumerators.getFormContextData('user');
16272
+ // eslint-disable-next-line
16273
+ const fileList = fileListValue && fileListValue();
16274
+ const {
16275
+ required,
16276
+ label,
16277
+ i18nKeyPrefix,
16278
+ visible
16279
+ } = props;
16280
+ const propertyId = i18nKeyPrefix;
16281
+ const rootPath = typeof path === 'string' ? path.replace(/(\.\d+|\[\d+\])$/, '') : path;
16282
+ const variant = (uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.variant) || 'button';
16283
+ const noDownloadButton = uischema == null || (_uischema$options2 = uischema.options) == null || (_uischema$options2 = _uischema$options2.format) == null ? void 0 : _uischema$options2.noDownloadButton;
16284
+ const noDownloadButtonInReview = uischema == null || (_uischema$options3 = uischema.options) == null || (_uischema$options3 = _uischema$options3.format) == null || (_uischema$options3 = _uischema$options3.review) == null ? void 0 : _uischema$options3.noDownloadButton;
16285
+ const noDeleteButton = uischema == null || (_uischema$options4 = uischema.options) == null || (_uischema$options4 = _uischema$options4.format) == null || (_uischema$options4 = _uischema$options4.review) == null ? void 0 : _uischema$options4.noDeleteButton;
16286
+ const isArraySchema = (props == null || (_props$schema = props.schema) == null ? void 0 : _props$schema.type) === 'array' || Array.isArray(data);
16287
+ const maxFiles = (_uischema$options$com = uischema == null || (_uischema$options5 = uischema.options) == null || (_uischema$options5 = _uischema$options5.componentProps) == null ? void 0 : _uischema$options5.maximum) != null ? _uischema$options$com : isArraySchema ? Number.MAX_SAFE_INTEGER : 1;
16288
+ const isMultiFile = maxFiles > 1 || isArraySchema;
16289
+ const metadataKey = path;
16290
+ const [deleteHide, setDeleteHide] = useState(false);
16291
+ const [deleteConfirmIndex, setDeleteConfirmIndex] = useState(null);
16292
+ const pendingUploadIndexRef = useRef(null);
16293
+ const uploadQueueRef = useRef(Promise.resolve());
16294
+ const filesForDisplay = useMemo(() => {
16295
+ if (!fileList) return [];
16296
+ if (isMultiFile) {
16297
+ const files = fileList[metadataKey] || fileList[rootPath] || fileList[propertyId] || [];
16298
+ const dataUrns = Array.isArray(data) ? data : data ? [data] : [];
16299
+ if (dataUrns.length > 0) {
16300
+ const urnSet = new Set(dataUrns);
16301
+ const scopedFiles = files.filter(f => urnSet.has(f.urn));
16302
+ if (scopedFiles.length > 0) {
16303
+ return scopedFiles.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
16304
+ }
16305
+ const allFiles = Object.values(fileList).flat();
16306
+ const filesByUrn = dataUrns.map(urn => allFiles.find(f => (f == null ? void 0 : f.urn) === urn)).filter(f => !!f);
16307
+ if (filesByUrn.length > 0) {
16308
+ return filesByUrn.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
16309
+ }
16310
+ }
16311
+ // Keep a stable list even if upstream metadata briefly duplicates entries.
16312
+ return files.filter((file, index, all) => all.findIndex(f => f.urn === file.urn) === index);
16313
+ }
16314
+ return fileList[metadataKey] || fileList[propertyId] || [];
16315
+ }, [fileList, isMultiFile, metadataKey, rootPath, propertyId, data]);
16316
+ const fileListLength = filesForDisplay.length;
16317
+ useEffect(() => {
16318
+ // Clear pending upload index when rendered file list catches up.
16319
+ pendingUploadIndexRef.current = null;
16320
+ }, [fileListLength, metadataKey, rootPath]);
16321
+ const getNextUploadIndex = () => {
16322
+ const baseIndex = filesForDisplay.length;
16323
+ if (pendingUploadIndexRef.current === null || pendingUploadIndexRef.current < baseIndex) {
16324
+ pendingUploadIndexRef.current = baseIndex;
16325
+ }
16326
+ const nextIndex = pendingUploadIndexRef.current;
16327
+ pendingUploadIndexRef.current += 1;
16328
+ return nextIndex;
16329
+ };
16330
+ async function uploadFile(file, requestedIndex) {
16331
+ if (!uploadTrigger) return;
16332
+ const fileListLength = requestedIndex != null ? requestedIndex : isMultiFile ? getNextUploadIndex() : filesForDisplay.length;
16333
+ // Single-file controls should allow selecting a new file to replace the current one.
16334
+ if (isMultiFile && fileListLength >= maxFiles) {
16335
+ setUploadError(`You can only upload up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}.`);
16336
+ return;
16337
+ }
16338
+ setUploadError(undefined);
16339
+ setLoadingFileName(file == null ? void 0 : file.name);
16340
+ await Promise.resolve(uploadTrigger(file, isMultiFile ? `${rootPath}.${fileListLength}` : path));
16341
+ setDeleteHide(false);
16342
+ }
16343
+ function queueUpload(file, requestedIndex) {
16344
+ uploadQueueRef.current = uploadQueueRef.current.then(() => uploadFile(file, requestedIndex)).catch(() => {
16345
+ // Keep queue alive after an individual upload failure.
16346
+ });
16347
+ }
16348
+ function downloadFile(file) {
16349
+ if (downloadTrigger && file) {
16350
+ downloadTrigger(file, propertyId);
16351
+ }
16352
+ }
16353
+ function deleteFile(file) {
16354
+ if (deleteTrigger && file) {
16355
+ deleteTrigger(file, propertyId);
16356
+ }
16357
+ }
16358
+ function getFileName(index) {
16359
+ var _getFile;
16360
+ return (_getFile = getFile(index)) == null ? void 0 : _getFile.filename;
16361
+ }
16362
+ function getFile(index) {
16363
+ return filesForDisplay == null ? void 0 : filesForDisplay[index];
16364
+ }
16365
+ useEffect(() => {
16366
+ if (loadingFileName !== undefined) {
16367
+ setLoadingFileName(undefined);
16368
+ }
16369
+ const delayedFunction = () => {
16370
+ if (!fileList) return;
16371
+ const filesForControl = filesForDisplay || [];
16372
+ const hasFileListEntryForPath = Object.prototype.hasOwnProperty.call(fileList, metadataKey) || Object.prototype.hasOwnProperty.call(fileList, rootPath) || !isMultiFile && Object.prototype.hasOwnProperty.call(fileList, propertyId);
16373
+ const urns = filesForControl.map(f => f.urn);
16374
+ if (urns.length === 0) {
16375
+ if (hasFileListEntryForPath && data !== undefined && data !== null && data !== '') {
16376
+ handleChange(isMultiFile ? rootPath : path, undefined);
16377
+ }
16378
+ } else if (isMultiFile) {
16379
+ handleChange(rootPath, urns);
16380
+ } else {
16381
+ // Single-file replacement appends metadata; keep the latest selection as the current value.
16382
+ handleChange(path, urns[urns.length - 1]);
16383
+ }
16384
+ };
16385
+ const timeoutId = setTimeout(delayedFunction, 1);
16386
+ return () => clearTimeout(timeoutId);
16387
+ }, [data, fileList, filesForDisplay, rootPath, path, propertyId, metadataKey, isMultiFile, handleChange, loadingFileName]);
16388
+ const readOnly = (uischema == null || (_uischema$options6 = uischema.options) == null || (_uischema$options6 = _uischema$options6.componentProps) == null ? void 0 : _uischema$options6.readOnly) === true || (props == null ? void 0 : props.isStepperReview) === true || user === null;
16389
+ const maxFileSize = (_uischema$options$com2 = uischema == null || (_uischema$options7 = uischema.options) == null || (_uischema$options7 = _uischema$options7.componentProps) == null ? void 0 : _uischema$options7.maxFileSize) != null ? _uischema$options$com2 : '';
16390
+ const accept = (_uischema$options$com3 = uischema == null || (_uischema$options8 = uischema.options) == null || (_uischema$options8 = _uischema$options8.componentProps) == null ? void 0 : _uischema$options8.accept) != null ? _uischema$options$com3 : '';
16391
+ if (!enumerators) {
16392
+ //eslint-disable-next-line
16393
+ return jsx(Fragment, {});
16394
+ }
16395
+ const helpText = uischema == null || (_uischema$options9 = uischema.options) == null ? void 0 : _uischema$options9.help;
16396
+ const sentenceCaseLabel = label;
16397
+ const renderFileItem = index => {
16398
+ var _getFile2;
16399
+ const showFileDeleteConfirmation = deleteConfirmIndex === index;
16400
+ return jsx("div", {
16401
+ children: readOnly ? jsxs(AttachmentBorderDisabled, {
16402
+ children: [getFileName(index), noDownloadButtonInReview !== true && jsx(GoAContextMenuIcon, {
16403
+ testId: "download-icon",
16404
+ title: "Download",
16405
+ type: "download",
16406
+ onClick: () => downloadFile(getFile(index))
16407
+ })]
16408
+ }) : jsxs(AttachmentBorder, {
16409
+ children: [jsx("div", {
16410
+ children: getFileName(index)
16411
+ }), jsxs(GoAContextMenu, {
16412
+ children: [noDownloadButton !== true && jsx(GoAContextMenuIcon, {
16413
+ testId: "download-icon",
16414
+ title: "Download",
16415
+ type: "download",
16416
+ onClick: () => downloadFile(getFile(index))
16417
+ }), noDeleteButton !== true && jsx(GoAContextMenuIcon, {
16418
+ "data-testid": "delete-icon",
16419
+ title: "Delete",
16420
+ type: "trash",
16421
+ onClick: () => {
16422
+ setDeleteConfirmIndex(index);
16423
+ }
16424
+ })]
16425
+ }), jsx(DeleteFileModal, {
16426
+ isOpen: showFileDeleteConfirmation,
16427
+ title: "Delete file",
16428
+ content: `Delete file ${(_getFile2 = getFile(index)) == null ? void 0 : _getFile2.filename} ?`,
16429
+ onCancel: () => setDeleteConfirmIndex(null),
16430
+ onDelete: () => {
16431
+ setDeleteConfirmIndex(null);
16432
+ deleteFile(getFile(index));
16433
+ if (!isMultiFile) {
16434
+ setDeleteHide(true);
16435
+ }
16436
+ setUploadError(undefined);
16437
+ }
16438
+ })]
16439
+ })
16440
+ });
16441
+ };
16442
+ return jsx(Visible, {
16443
+ "$visible": visible,
16444
+ children: jsxs(FileUploaderStyle, {
16445
+ className: "FileUploader",
16446
+ children: [jsx(GoabFormItem, {
16447
+ label: sentenceCaseLabel,
16448
+ requirement: required ? 'required' : undefined,
16449
+ error: uploadError
16450
+ }), !readOnly && jsx("div", {
16451
+ className: "file-upload",
16452
+ children: jsx(GoabFileUploadInput, {
16453
+ variant: variant,
16454
+ onSelectFile: detail => {
16455
+ var _detail$files;
16456
+ const selectedFiles = detail != null && (_detail$files = detail.files) != null && _detail$files.length ? detail.files : detail != null && detail.file ? [detail.file] : [];
16457
+ if (selectedFiles.length === 0) {
16458
+ return;
16459
+ }
16460
+ if (isMultiFile) {
16461
+ for (const selectedFile of selectedFiles) {
16462
+ const nextIndex = getNextUploadIndex();
16463
+ if (nextIndex >= maxFiles) {
16464
+ setUploadError(`You can only upload up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}.`);
16465
+ break;
16466
+ }
16467
+ queueUpload(selectedFile, nextIndex);
16468
+ }
16469
+ } else {
16470
+ queueUpload(selectedFiles[0]);
16471
+ }
16472
+ },
16473
+ maxFileSize: maxFileSize,
16474
+ accept: accept
16475
+ })
16476
+ }), helpText && jsx(HelpText, {
16477
+ children: helpText
16478
+ }), jsx("div", {
16479
+ children: loadingFileName !== undefined ? jsx(GoabModal, {
16480
+ open: loadingFileName !== undefined,
16481
+ children: jsx("div", {
16482
+ className: "align-center",
16483
+ children: jsx(GoabCircularProgress, {
16484
+ visible: true,
16485
+ message: `Uploading ${loadingFileName}`,
16486
+ size: "large"
16487
+ })
16488
+ })
16489
+ }) : jsx("div", {
16490
+ children: (fileList && isMultiFile ? filesForDisplay.map((_, i) => i) : !deleteHide && getFile(fileListLength - 1) && fileListLength >= 0 ? [fileListLength - 1] : []).map(index => jsx(React.Fragment, {
16491
+ children: renderFileItem(index)
16492
+ }, index))
16493
+ })
16494
+ })]
16495
+ })
16496
+ });
16497
+ };
16498
+ const HelpText = styled.div(_t$1 || (_t$1 = _2`
16499
+ margin-top: var(--goa-space-xs);
16500
+ font-size: var(--goa-font-size-3);
16501
+ color: var(--goa-color-text-secondary);
16502
+ `));
16503
+ const AttachmentBorderDisabled = styled.div(_t2$1 || (_t2$1 = _2`
16504
+ display: flex;
16505
+ flex-direction: row;
16506
+ border: var(--goa-border-width-s) solid #dcdcdc;
16507
+ border-radius: var(--goa-border-radius-m);
16508
+ padding: var(--goa-space-xs);
16509
+ width: fit-content;
16510
+ background-color: #f1f1f1;
16511
+ `));
16512
+ const AttachmentBorder = styled.div(_t3 || (_t3 = _2`
16513
+ display: flex;
16514
+ flex-direction: row;
16515
+ border: var(--goa-border-width-s) solid #dcdcdc;
16516
+ border-radius: var(--goa-border-radius-m);
16517
+ padding: var(--goa-space-xs);
16518
+ width: fit-content;
16519
+ margin-top: var(--goa-space-2xs);
16520
+ `));
16521
+ const FileUploaderStyle = styled.div(_t4 || (_t4 = _2`
16522
+ margin-bottom: var(--goa-space-l);
16523
+ .label {
16524
+ display: block;
16525
+ font-weight: var(--goa-font-weight-bold);
16526
+ color: var(--goa-color-text-default);
16527
+ font-size: var(--goa-font-size-4);
16528
+ padding: 0 0 var(--goa-space-xs) 0;
16529
+ }
16530
+
16531
+ .align-center {
16532
+ text-align-last: center;
16533
+ }
16534
+
16535
+ .file-upload {
16536
+ margin-bottom: var(--goa-space-xs);
16537
+ }
16538
+ `));
16539
+
16175
16540
  const ArrayControl = props => {
16176
16541
  const {
16177
16542
  visible,
@@ -16228,6 +16593,8 @@ const PrimitiveArrayControl = props => {
16228
16593
  cells
16229
16594
  } = props;
16230
16595
  const enumerators = useContext(JsonFormContext);
16596
+ const itemSchema = schema == null ? void 0 : schema.items;
16597
+ const isFileUrnArray = (itemSchema == null ? void 0 : itemSchema.format) === 'file-urn';
16231
16598
  const rawItems = Array.isArray(data) ? data : [];
16232
16599
  const items = rawItems.filter(item => item !== undefined && item !== null);
16233
16600
  const deleteTriggerFunction = enumerators == null || (_enumerators$function = enumerators.functions) == null ? void 0 : _enumerators$function.get('delete-file');
@@ -16239,6 +16606,14 @@ const PrimitiveArrayControl = props => {
16239
16606
  handleChange(path, items.length > 0 ? items : undefined);
16240
16607
  }
16241
16608
  }, [rawItems, items, handleChange, path]);
16609
+ if (isFileUrnArray) {
16610
+ return jsx(Visible, {
16611
+ "$visible": visible,
16612
+ children: jsx(FileUploader, Object.assign({}, props, {
16613
+ data: items
16614
+ }))
16615
+ });
16616
+ }
16242
16617
  const addItem = () => {
16243
16618
  handleChange(path, [...items, '']);
16244
16619
  };
@@ -16246,7 +16621,6 @@ const PrimitiveArrayControl = props => {
16246
16621
  const getOptionLabel = option => typeof option === 'string' ? option : option.title || option.const;
16247
16622
  const getOptionDescription = option => typeof option === 'string' ? undefined : option.description;
16248
16623
  const removeItem = index => {
16249
- const itemSchema = schema == null ? void 0 : schema.items;
16250
16624
  const removedItem = items[index];
16251
16625
  const itemPath = composePaths(path, `${index}`);
16252
16626
  if ((itemSchema == null ? void 0 : itemSchema.format) === 'file-urn' && deleteTrigger && removedItem) {
@@ -16922,10 +17296,10 @@ const GoAGroupReviewControlComponent = props => {
16922
17296
  const GoAGroupReviewLayoutTester = rankWith(1, uiTypeIs('Group'));
16923
17297
  const GoAGroupReviewControl = withJsonFormsLayoutProps(GoAGroupReviewControlComponent, true);
16924
17298
 
16925
- let _$1 = t => t,
16926
- _t$2,
16927
- _t2$1;
16928
- const HelpContentDiv = styled.div(_t$2 || (_t$2 = _$1`
17299
+ let _ = t => t,
17300
+ _t,
17301
+ _t2;
17302
+ const HelpContentDiv = styled.div(_t || (_t = _`
16929
17303
  .parent-label {
16930
17304
  font-size: 24px;
16931
17305
  margin-bottom: var(--goa-space-m);
@@ -17005,45 +17379,17 @@ const HelpContentDiv = styled.div(_t$2 || (_t$2 = _$1`
17005
17379
  top: 2.2rem;
17006
17380
  bottom: 0.5rem;
17007
17381
  width: 2px;
17008
- background-color: #ccc;
17009
- pointer-events: none;
17010
- }
17011
-
17012
- .help-content-markdown summary {
17013
- text-decoration: underline;
17014
- }
17015
- `));
17016
- const InvalidMarkdown = styled.div(_t2$1 || (_t2$1 = _$1`
17017
- color: var(--goa-color-interactive-error);
17018
- `));
17019
-
17020
- let _ = t => t,
17021
- _t$1;
17022
- const GoAContextMenuIcon = props => {
17023
- return jsx(GoabIconButton, {
17024
- icon: props.type,
17025
- onClick: props.onClick,
17026
- title: props.title,
17027
- testId: props.testId,
17028
- size: "small",
17029
- disabled: props.disabled
17030
- });
17031
- };
17032
- const GoAContextMenu = styled.div(_t$1 || (_t$1 = _`
17033
- display: flex;
17034
- align-items: center;
17035
- background-color: #fff;
17036
- gap: var(--goa-space-2xs);
17037
-
17038
- > .goa-icon-button {
17039
- cursor: pointer;
17040
- border-radius: var(--goa-border-radius-m);
17041
- padding: var(--goa-space-2xs);
17382
+ background-color: #ccc;
17383
+ pointer-events: none;
17042
17384
  }
17043
- > .goa-icon-button + .goa-icon-button {
17044
- margin-left: var(--goa-space-none);
17385
+
17386
+ .help-content-markdown summary {
17387
+ text-decoration: underline;
17045
17388
  }
17046
17389
  `));
17390
+ const InvalidMarkdown = styled.div(_t2 || (_t2 = _`
17391
+ color: var(--goa-color-interactive-error);
17392
+ `));
17047
17393
 
17048
17394
  const linkLength = 40;
17049
17395
  const invalidExtensions = ['exe'];
@@ -17105,12 +17451,12 @@ const RenderLink = props => {
17105
17451
  });
17106
17452
  };
17107
17453
 
17108
- const _excluded$3 = ["node"],
17454
+ const _excluded$2 = ["node"],
17109
17455
  _excluded2 = ["isParent", "showLabel"];
17110
17456
  const markdownComponents = {
17111
17457
  // Destructure node out (react-markdown internal prop) so it is not forwarded to the DOM element.
17112
17458
  a: _ref => {
17113
- let props = _objectWithoutPropertiesLoose(_ref, _excluded$3);
17459
+ let props = _objectWithoutPropertiesLoose(_ref, _excluded$2);
17114
17460
  return jsx("a", Object.assign({}, props, {
17115
17461
  target: "_blank",
17116
17462
  rel: "noopener noreferrer"
@@ -17952,7 +18298,7 @@ const SummaryRow = ({
17952
18298
  });
17953
18299
  };
17954
18300
 
17955
- const _excluded$2 = ["type"];
18301
+ const _excluded$1 = ["type"];
17956
18302
  const AdditionalInstructionsRow = ({
17957
18303
  additionalInstructions,
17958
18304
  componentProps
@@ -17961,7 +18307,7 @@ const AdditionalInstructionsRow = ({
17961
18307
  const calloutType = (componentProps == null ? void 0 : componentProps.type) || 'information';
17962
18308
  const type = validTypes.includes(calloutType) ? calloutType : 'information';
17963
18309
  const _ref = componentProps || {},
17964
- otherProps = _objectWithoutPropertiesLoose(_ref, _excluded$2);
18310
+ otherProps = _objectWithoutPropertiesLoose(_ref, _excluded$1);
17965
18311
  const sanitizedHtml = sanitizeHtml(additionalInstructions);
17966
18312
  return jsx("tr", {
17967
18313
  children: jsx("td", {
@@ -18452,280 +18798,14 @@ const CategorizationPagesRendererTester = rankWith(2, and(uiTypeIs('Categorizati
18452
18798
  return ((_uischema$options3 = uischema.options) == null ? void 0 : _uischema$options3.variant) === 'pages';
18453
18799
  }));
18454
18800
 
18455
- const DeleteFileModal = ({
18456
- isOpen,
18457
- title,
18458
- content,
18459
- onDelete,
18460
- onCancel
18461
- }) => {
18462
- return jsx(GoabModal, {
18463
- testId: "delete-confirmation",
18464
- open: isOpen,
18465
- heading: title,
18466
- maxWidth: "640px",
18467
- actions: jsxs(GoabButtonGroup, {
18468
- alignment: "end",
18469
- children: [jsx(GoabButton, {
18470
- type: "secondary",
18471
- testId: "delete-cancel",
18472
- onClick: onCancel,
18473
- children: "Cancel"
18474
- }), jsx(GoabButton, {
18475
- type: "primary",
18476
- variant: "destructive",
18477
- testId: "delete-confirm",
18478
- onClick: onDelete,
18479
- children: "Delete"
18480
- })]
18481
- }),
18482
- children: content
18483
- });
18484
- };
18485
-
18486
- let _2 = t => t,
18487
- _t,
18488
- _t2,
18489
- _t3,
18490
- _t4;
18491
- const _excluded$1 = ["data", "path", "handleChange", "uischema"];
18492
- const FileUploaderReview = props => {
18493
- return FileUploader(Object.assign({}, props, {
18494
- isStepperReview: true
18495
- }));
18496
- };
18497
- const FileUploader = _ref => {
18498
- var _enumerators$function, _enumerators$function2, _enumerators$function3, _uischema$options, _uischema$options2, _uischema$options3, _uischema$options4, _fileList$path, _uischema$options$com, _uischema$options5, _uischema$options6, _uischema$options$com2, _uischema$options7, _uischema$options$com3, _uischema$options8, _uischema$options9;
18499
- let {
18500
- data,
18501
- path,
18502
- handleChange,
18503
- uischema
18504
- } = _ref,
18505
- props = _objectWithoutPropertiesLoose(_ref, _excluded$1);
18506
- const enumerators = useContext(JsonFormContext);
18507
- const uploadTriggerFunction = enumerators == null || (_enumerators$function = enumerators.functions) == null ? void 0 : _enumerators$function.get('upload-file');
18508
- const uploadTrigger = uploadTriggerFunction && uploadTriggerFunction();
18509
- const downloadTriggerFunction = enumerators == null || (_enumerators$function2 = enumerators.functions) == null ? void 0 : _enumerators$function2.get('download-file');
18510
- const downloadTrigger = downloadTriggerFunction && downloadTriggerFunction();
18511
- const deleteTriggerFunction = enumerators == null || (_enumerators$function3 = enumerators.functions) == null ? void 0 : _enumerators$function3.get('delete-file');
18512
- const deleteTrigger = deleteTriggerFunction && deleteTriggerFunction();
18513
- const fileListValue = enumerators == null ? void 0 : enumerators.data.get('file-list');
18514
- const [loadingFileName, setLoadingFileName] = useState(undefined);
18515
- const [uploadError, setUploadError] = useState(undefined);
18516
- const countries = ['Argentina', 'Brazil', 'Canada', 'Denmark', 'Egypt', 'France', 'Greece', 'India', 'Japan', 'Kenya'];
18517
- enumerators == null || enumerators.addFormContextData('countries', countries);
18518
- const user = enumerators == null ? void 0 : enumerators.getFormContextData('user');
18519
- // eslint-disable-next-line
18520
- const fileList = fileListValue && fileListValue();
18521
- const {
18522
- required,
18523
- label,
18524
- i18nKeyPrefix,
18525
- visible
18526
- } = props;
18527
- const propertyId = i18nKeyPrefix;
18528
- const variant = (uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.variant) || 'button';
18529
- const noDownloadButton = uischema == null || (_uischema$options2 = uischema.options) == null || (_uischema$options2 = _uischema$options2.format) == null ? void 0 : _uischema$options2.noDownloadButton;
18530
- const noDownloadButtonInReview = uischema == null || (_uischema$options3 = uischema.options) == null || (_uischema$options3 = _uischema$options3.format) == null || (_uischema$options3 = _uischema$options3.review) == null ? void 0 : _uischema$options3.noDownloadButton;
18531
- const noDeleteButton = uischema == null || (_uischema$options4 = uischema.options) == null || (_uischema$options4 = _uischema$options4.format) == null || (_uischema$options4 = _uischema$options4.review) == null ? void 0 : _uischema$options4.noDeleteButton;
18532
- const [deleteHide, setDeleteHide] = useState(false);
18533
- const [deleteConfirmIndex, setDeleteConfirmIndex] = useState(null);
18534
- const fileListLength = fileList && ((_fileList$path = fileList[path]) == null ? void 0 : _fileList$path.length) || 0;
18535
- const maxFiles = (_uischema$options$com = uischema == null || (_uischema$options5 = uischema.options) == null || (_uischema$options5 = _uischema$options5.componentProps) == null ? void 0 : _uischema$options5.maximum) != null ? _uischema$options$com : 1;
18536
- const isMultiFile = maxFiles > 1;
18537
- function uploadFile(file) {
18538
- var _fileList$propertyId;
18539
- if (!uploadTrigger) return;
18540
- const fileListLength = fileList && ((_fileList$propertyId = fileList[propertyId]) == null ? void 0 : _fileList$propertyId.length) || 0;
18541
- if (fileListLength >= maxFiles) {
18542
- setUploadError(`You can only upload up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}.`);
18543
- return;
18544
- }
18545
- setUploadError(undefined);
18546
- setLoadingFileName(file == null ? void 0 : file.name);
18547
- uploadTrigger(file, path);
18548
- setDeleteHide(false);
18549
- }
18550
- function downloadFile(file) {
18551
- if (downloadTrigger) {
18552
- downloadTrigger(file, propertyId);
18553
- }
18554
- }
18555
- function deleteFile(file) {
18556
- if (deleteTrigger) {
18557
- deleteTrigger(file, propertyId);
18558
- }
18559
- }
18560
- function getFileName(index) {
18561
- var _getFile;
18562
- return (_getFile = getFile(index)) == null ? void 0 : _getFile.filename;
18563
- }
18564
- function getFile(index) {
18565
- var _fileList$path2;
18566
- return fileList == null || (_fileList$path2 = fileList[path]) == null ? void 0 : _fileList$path2[index];
18567
- }
18568
- useEffect(() => {
18569
- if (loadingFileName !== undefined) {
18570
- setLoadingFileName(undefined);
18571
- }
18572
- const delayedFunction = () => {
18573
- if (!fileList) return;
18574
- const filesForControl = (fileList == null ? void 0 : fileList[path]) || [];
18575
- const hasFileListEntryForPath = Object.prototype.hasOwnProperty.call(fileList, path);
18576
- const urns = filesForControl.map(f => f.urn);
18577
- if (urns.length === 0) {
18578
- if (hasFileListEntryForPath && data !== undefined && data !== null && data !== '') {
18579
- handleChange(path, undefined);
18580
- }
18581
- } else if (isMultiFile) {
18582
- handleChange(path, urns);
18583
- } else {
18584
- handleChange(path, urns[0]);
18585
- }
18586
- };
18587
- const timeoutId = setTimeout(delayedFunction, 1);
18588
- return () => clearTimeout(timeoutId);
18589
- //eslint-disable-next-line
18590
- }, [data, fileList, path, propertyId, isMultiFile, handleChange, loadingFileName]);
18591
- const readOnly = (uischema == null || (_uischema$options6 = uischema.options) == null || (_uischema$options6 = _uischema$options6.componentProps) == null ? void 0 : _uischema$options6.readOnly) === true || (props == null ? void 0 : props.isStepperReview) === true || user === null;
18592
- const maxFileSize = (_uischema$options$com2 = uischema == null || (_uischema$options7 = uischema.options) == null || (_uischema$options7 = _uischema$options7.componentProps) == null ? void 0 : _uischema$options7.maxFileSize) != null ? _uischema$options$com2 : '';
18593
- const accept = (_uischema$options$com3 = uischema == null || (_uischema$options8 = uischema.options) == null || (_uischema$options8 = _uischema$options8.componentProps) == null ? void 0 : _uischema$options8.accept) != null ? _uischema$options$com3 : '';
18594
- if (!enumerators) {
18595
- //eslint-disable-next-line
18596
- return jsx(Fragment, {});
18597
- }
18598
- const helpText = uischema == null || (_uischema$options9 = uischema.options) == null ? void 0 : _uischema$options9.help;
18599
- const sentenceCaseLabel = label;
18600
- const renderFileItem = index => {
18601
- var _getFile2;
18602
- const showFileDeleteConfirmation = deleteConfirmIndex === index;
18603
- return jsx("div", {
18604
- children: readOnly ? jsxs(AttachmentBorderDisabled, {
18605
- children: [getFileName(index), noDownloadButtonInReview !== true && jsx(GoAContextMenuIcon, {
18606
- testId: "download-icon",
18607
- title: "Download",
18608
- type: "download",
18609
- onClick: () => downloadFile(getFile(index))
18610
- })]
18611
- }) : jsxs(AttachmentBorder, {
18612
- children: [jsx("div", {
18613
- children: getFileName(index)
18614
- }), jsxs(GoAContextMenu, {
18615
- children: [noDownloadButton !== true && jsx(GoAContextMenuIcon, {
18616
- testId: "download-icon",
18617
- title: "Download",
18618
- type: "download",
18619
- onClick: () => downloadFile(getFile(index))
18620
- }), noDeleteButton !== true && jsx(GoAContextMenuIcon, {
18621
- "data-testid": "delete-icon",
18622
- title: "Delete",
18623
- type: "trash",
18624
- onClick: () => {
18625
- setDeleteConfirmIndex(index);
18626
- }
18627
- })]
18628
- }), jsx(DeleteFileModal, {
18629
- isOpen: showFileDeleteConfirmation,
18630
- title: "Delete file",
18631
- content: `Delete file ${(_getFile2 = getFile(index)) == null ? void 0 : _getFile2.filename} ?`,
18632
- onCancel: () => setDeleteConfirmIndex(null),
18633
- onDelete: () => {
18634
- setDeleteConfirmIndex(null);
18635
- deleteFile(getFile(index));
18636
- if (!isMultiFile) {
18637
- setDeleteHide(true);
18638
- }
18639
- setUploadError(undefined);
18640
- }
18641
- })]
18642
- })
18643
- });
18644
- };
18645
- return jsx(Visible, {
18646
- "$visible": visible,
18647
- children: jsxs(FileUploaderStyle, {
18648
- className: "FileUploader",
18649
- children: [jsx(GoabFormItem, {
18650
- label: sentenceCaseLabel,
18651
- requirement: required ? 'required' : undefined,
18652
- error: uploadError
18653
- }), !readOnly && jsx("div", {
18654
- className: "file-upload",
18655
- children: jsx(GoabFileUploadInput, {
18656
- variant: variant,
18657
- onSelectFile: detail => {
18658
- // adjust based on the actual shape of "detail"
18659
- uploadFile(detail.file); // or detail.files[0], etc.
18660
- },
18661
- maxFileSize: maxFileSize,
18662
- accept: accept
18663
- })
18664
- }), helpText && jsx(HelpText, {
18665
- children: helpText
18666
- }), jsx("div", {
18667
- children: loadingFileName !== undefined ? jsx(GoabModal, {
18668
- open: loadingFileName !== undefined,
18669
- children: jsx("div", {
18670
- className: "align-center",
18671
- children: jsx(GoabCircularProgress, {
18672
- visible: true,
18673
- message: `Uploading ${loadingFileName}`,
18674
- size: "large"
18675
- })
18676
- })
18677
- }) : jsx("div", {
18678
- children: (fileList && isMultiFile ? (fileList[path] || []).map((_, i) => i) : !deleteHide && getFile(fileListLength - 1) && fileListLength >= 0 ? [fileListLength - 1] : []).map(index => jsx(React.Fragment, {
18679
- children: renderFileItem(index)
18680
- }, index))
18681
- })
18682
- })]
18683
- })
18684
- });
18685
- };
18686
- const HelpText = styled.div(_t || (_t = _2`
18687
- margin-top: var(--goa-space-xs);
18688
- font-size: var(--goa-font-size-3);
18689
- color: var(--goa-color-text-secondary);
18690
- `));
18691
- const AttachmentBorderDisabled = styled.div(_t2 || (_t2 = _2`
18692
- display: flex;
18693
- flex-direction: row;
18694
- border: var(--goa-border-width-s) solid #dcdcdc;
18695
- border-radius: var(--goa-border-radius-m);
18696
- padding: var(--goa-space-xs);
18697
- width: fit-content;
18698
- background-color: #f1f1f1;
18699
- `));
18700
- const AttachmentBorder = styled.div(_t3 || (_t3 = _2`
18701
- display: flex;
18702
- flex-direction: row;
18703
- border: var(--goa-border-width-s) solid #dcdcdc;
18704
- border-radius: var(--goa-border-radius-m);
18705
- padding: var(--goa-space-xs);
18706
- width: fit-content;
18707
- margin-top: var(--goa-space-2xs);
18708
- `));
18709
- const FileUploaderStyle = styled.div(_t4 || (_t4 = _2`
18710
- margin-bottom: var(--goa-space-l);
18711
- .label {
18712
- display: block;
18713
- font-weight: var(--goa-font-weight-bold);
18714
- color: var(--goa-color-text-default);
18715
- font-size: var(--goa-font-size-4);
18716
- padding: 0 0 var(--goa-space-xs) 0;
18717
- }
18718
-
18719
- .align-center {
18720
- text-align-last: center;
18721
- }
18722
-
18723
- .file-upload {
18724
- margin-bottom: var(--goa-space-xs);
18801
+ const isSingleFileUrn = and(schemaTypeIs('string'), formatIs('file-urn'));
18802
+ const isFileUrnArray = and(schemaTypeIs('array'), schemaMatches(schema => {
18803
+ if (!(schema != null && schema.items) || Array.isArray(schema.items)) {
18804
+ return false;
18725
18805
  }
18726
- `));
18727
-
18728
- const FileUploaderTester = rankWith(3, and(schemaTypeIs('string'), formatIs('file-urn')));
18806
+ return schema.items.type === 'string' && schema.items.format === 'file-urn';
18807
+ }));
18808
+ const FileUploaderTester = rankWith(3, or(isSingleFileUrn, isFileUrnArray));
18729
18809
 
18730
18810
  const AddressInputs = ({
18731
18811
  address,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/jsonforms-components",
3
- "version": "2.79.3",
3
+ "version": "2.79.4",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Government of Alberta - React renderers for JSON Forms based on the design system.",
6
6
  "repository": "https://github.com/GovAlta/adsp-monorepo",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-10-26T17:03:28.720Z",
4
- "sourceCommit": "7ae3adca736763caffcfe99762c69224c7c0032a",
3
+ "generatedAt": "2026-10-28T20:42:38.992Z",
4
+ "sourceCommit": "dc35c087a12660681557962655deb565941cc540",
5
5
  "sourcePath": "libs/jsonforms-components/src/index.ts",
6
6
  "rendererCount": 23,
7
7
  "renderers": [