@abgov/jsonforms-components 2.38.2 → 2.38.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
@@ -6450,8 +6450,8 @@ const RadioGroup = props => {
6450
6450
  const appliedUiSchemaOptions = merge({}, config, props.uischema.options, options);
6451
6451
  return jsx(GoARadioGroup, Object.assign({
6452
6452
  error: isVisited && errors.length > 0,
6453
- name: `${options || appliedUiSchemaOptions.label}`,
6454
- testId: `${label || id}-jsonforms-radio`,
6453
+ name: `${path || appliedUiSchemaOptions.label}`,
6454
+ testId: `${path || id || label}-radio-group`,
6455
6455
  value: data,
6456
6456
  disabled: !enabled
6457
6457
  }, appliedUiSchemaOptions, {
@@ -7089,7 +7089,7 @@ let _$6 = t => t,
7089
7089
  _t20$1,
7090
7090
  _t21$1,
7091
7091
  _t22$1,
7092
- _t23,
7092
+ _t23$1,
7093
7093
  _t24,
7094
7094
  _t25,
7095
7095
  _t26,
@@ -7248,7 +7248,7 @@ const TableReviewCategoryLabel = styled.h3(_t22$1 || (_t22$1 = _$6`
7248
7248
  color: var(--goa-color-text-secondary) !important;
7249
7249
  margin-bottom: var(--goa-space-l);
7250
7250
  `));
7251
- const CategoryStatus = styled.td(_t23 || (_t23 = _$6`
7251
+ const CategoryStatus = styled.td(_t23$1 || (_t23$1 = _$6`
7252
7252
  width: var(--goa-space-xl);
7253
7253
  padding-right: var(--goa-space-xl);
7254
7254
  align-content: center;
@@ -9930,7 +9930,8 @@ let _$3 = t => t,
9930
9930
  _t19,
9931
9931
  _t20,
9932
9932
  _t21,
9933
- _t22;
9933
+ _t22,
9934
+ _t23;
9934
9935
  const DeleteDialogContent = styled.div(_t$3 || (_t$3 = _$3`
9935
9936
  margin-bottom: var(--goa-space-m);
9936
9937
  `));
@@ -9985,7 +9986,7 @@ const FlexForm = styled.div(_t10 || (_t10 = _$3`
9985
9986
  flex-direction: column;
9986
9987
  flex: 3;
9987
9988
  `));
9988
- const TabData = styled.div(_t11 || (_t11 = _$3`
9989
+ const TabName = styled.div(_t11 || (_t11 = _$3`
9989
9990
  margin: 1rem 0 1rem 1rem;
9990
9991
  font-weight: 400;
9991
9992
  white-space: nowrap;
@@ -10047,6 +10048,15 @@ styled.div(_t21 || (_t21 = _$3`
10047
10048
  const HilightCellWarning = styled.div(_t22 || (_t22 = _$3`
10048
10049
  background-color: var(--goa-color-warning-default);
10049
10050
  `));
10051
+ const FixTableHeaderAlignment = styled.div(_t23 || (_t23 = _$3`
10052
+ table thead th:nth-child(3) {
10053
+ text-align: center;
10054
+ }
10055
+
10056
+ table tbody td:nth-child(3) {
10057
+ text-align: center;
10058
+ }
10059
+ `));
10050
10060
 
10051
10061
  const DeleteDialog = /*#__PURE__*/React.memo(function DeleteDialog({
10052
10062
  open,
@@ -10375,140 +10385,145 @@ const NonEmptyCellComponent$1 = /*#__PURE__*/React.memo(function NonEmptyCellCom
10375
10385
  cells: cells
10376
10386
  }, rowPath);
10377
10387
  }), properties && Object.keys(properties).length > 0 && jsxs(Fragment, {
10378
- children: [jsxs(GoATable, {
10379
- width: "100%",
10380
- children: [jsx("thead", {
10381
- children: jsxs("tr", {
10382
- children: [Object.entries(tableKeys).map(([value, index]) => {
10383
- const currentProperty = properties[value];
10384
- if (!isInReview) {
10385
- return jsx("th", {
10388
+ children: [jsx(FixTableHeaderAlignment, {
10389
+ children: jsxs(GoATable, {
10390
+ width: "100%",
10391
+ children: [jsx("thead", {
10392
+ children: jsxs("tr", {
10393
+ children: [Object.entries(tableKeys).map(([value, index]) => {
10394
+ const currentProperty = properties[value];
10395
+ if (!isInReview) {
10396
+ return jsx("th", {
10397
+ children: jsxs("p", {
10398
+ children: [(currentProperty === null || currentProperty === void 0 ? void 0 : currentProperty.title) || convertToSentenceCase(index), (required === null || required === void 0 ? void 0 : required.includes(value)) && jsx(RequiredSpan, {
10399
+ children: "(required)"
10400
+ })]
10401
+ })
10402
+ }, index);
10403
+ }
10404
+ return jsx(TableTHHeader, {
10386
10405
  children: jsxs("p", {
10387
- children: [(currentProperty === null || currentProperty === void 0 ? void 0 : currentProperty.title) || convertToSentenceCase(index), (required === null || required === void 0 ? void 0 : required.includes(value)) && jsx(RequiredSpan, {
10388
- children: "(required)"
10406
+ children: [`${(currentProperty === null || currentProperty === void 0 ? void 0 : currentProperty.title) || convertToSentenceCase(index)}`, (required === null || required === void 0 ? void 0 : required.includes(value)) && jsxs(RequiredSpan, {
10407
+ children: [jsx("br", {}), " (required)"]
10389
10408
  })]
10390
10409
  })
10391
10410
  }, index);
10392
- }
10393
- return jsx(TableTHHeader, {
10394
- children: jsxs("p", {
10395
- children: [`${(currentProperty === null || currentProperty === void 0 ? void 0 : currentProperty.title) || convertToSentenceCase(index)}`, (required === null || required === void 0 ? void 0 : required.includes(value)) && jsxs(RequiredSpan, {
10396
- children: [jsx("br", {}), " (required)"]
10397
- })]
10411
+ }), isInReview !== true && jsx("th", {
10412
+ children: jsx("p", {
10413
+ children: "Actions"
10398
10414
  })
10399
- }, index);
10400
- }), isInReview !== true && jsx("th", {
10401
- children: jsx("p", {
10402
- children: "Actions"
10403
- })
10404
- })]
10405
- }, 0)
10406
- }), jsx("tbody", {
10407
- children: range(count || 0).map((num, i) => {
10408
- const errorRow = errors === null || errors === void 0 ? void 0 : errors.find(error => error.instancePath.includes(`/${props.rowPath.replace(/\./g, '/')}/${i}`));
10409
- return jsxs("tr", {
10410
- children: [Object.keys(properties).map((element, ix) => {
10411
- var _a, _b;
10412
- const dataObject = properties[element];
10413
- const schemaName = element;
10414
- const currentData = data && data[num] ? data[num][element] : '';
10415
- //Get out of the loop to not render extra blank columns at the end of the table
10416
- if (ix > 1 && Object.keys(tableKeys).length === ix) return null;
10417
- const error = (errors === null || errors === void 0 ? void 0 : errors.filter(e => e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}/${element}` || e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}`)).find(y => {
10418
- var _a;
10419
- return ((_a = y === null || y === void 0 ? void 0 : y.message) === null || _a === void 0 ? void 0 : _a.includes(element)) || y.instancePath.includes(element);
10420
- });
10421
- if ((error === null || error === void 0 ? void 0 : error.message.includes('must NOT have fewer')) && required.find(r => r === schemaName) && (isEmptyBoolean(schema, currentData) || isEmptyNumber(schema, currentData))) {
10422
- error.message = `${capitalizeFirstLetter(schemaName)} is required`;
10423
- }
10424
- if (isInReview === true) {
10415
+ })]
10416
+ }, 0)
10417
+ }), jsx("tbody", {
10418
+ children: range(count || 0).map((num, i) => {
10419
+ const errorRow = errors === null || errors === void 0 ? void 0 : errors.find(error => error.instancePath.includes(`/${props.rowPath.replace(/\./g, '/')}/${i}`));
10420
+ return jsxs("tr", {
10421
+ children: [Object.keys(properties).map((element, ix) => {
10422
+ var _a, _b;
10423
+ const dataObject = properties[element];
10424
+ const schemaName = element;
10425
+ const currentData = data && data[num] ? data[num][element] : '';
10426
+ //Get out of the loop to not render extra blank columns at the end of the table
10427
+ if (ix > 1 && Object.keys(tableKeys).length === ix) return null;
10428
+ const error = (errors === null || errors === void 0 ? void 0 : errors.filter(e => e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}/${element}` || e.instancePath === `/${props.rowPath.replace(/\./g, '/')}/${i}`)).find(y => {
10429
+ var _a;
10430
+ return ((_a = y === null || y === void 0 ? void 0 : y.message) === null || _a === void 0 ? void 0 : _a.includes(element)) || y.instancePath.includes(element);
10431
+ });
10432
+ if ((error === null || error === void 0 ? void 0 : error.message.includes('must NOT have fewer')) && required.find(r => r === schemaName) && (isEmptyBoolean(schema, currentData) || isEmptyNumber(schema, currentData))) {
10433
+ error.message = `${capitalizeFirstLetter(schemaName)} is required`;
10434
+ }
10435
+ if (isInReview === true) {
10436
+ return jsx("td", {
10437
+ children: jsx("div", {
10438
+ "data-testid": `#/properties/${schemaName}-input-${i}-review`,
10439
+ style: {
10440
+ display: 'block'
10441
+ },
10442
+ children: renderCellColumn({
10443
+ data: currentData ? String(currentData) : undefined,
10444
+ error: error === null || error === void 0 ? void 0 : error.message,
10445
+ isRequired: (_a = required === null || required === void 0 ? void 0 : required.includes(tableKeys[element])) !== null && _a !== void 0 ? _a : false,
10446
+ errors: errors !== undefined ? errors : [],
10447
+ element,
10448
+ rowPath,
10449
+ index: i
10450
+ })
10451
+ })
10452
+ }, ix);
10453
+ }
10425
10454
  return jsx("td", {
10426
- children: jsx("div", {
10427
- "data-testid": `#/properties/${schemaName}-input-${i}-review`,
10428
- children: renderCellColumn({
10429
- data: currentData ? String(currentData) : undefined,
10430
- error: error === null || error === void 0 ? void 0 : error.message,
10431
- isRequired: (_a = required === null || required === void 0 ? void 0 : required.includes(tableKeys[element])) !== null && _a !== void 0 ? _a : false,
10432
- errors: errors !== undefined ? errors : [],
10433
- element,
10434
- rowPath,
10435
- index: i
10455
+ children: jsx(GoAFormItem, {
10456
+ error: (_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : '',
10457
+ mb: errorRow && !error && '2xl' || 'xs',
10458
+ children: dataObject.enum ? jsxs(GoADropdown, {
10459
+ id: schemaName,
10460
+ name: schemaName,
10461
+ value: currentData != null ? String(currentData) : '',
10462
+ testId: `#/properties/${schemaName}-select-${i}`,
10463
+ onChange: (name, value) => {
10464
+ const selectedValue = Array.isArray(value) ? value[0] : value;
10465
+ const coerced = dataObject.type === 'number' && selectedValue !== '' ? Number(selectedValue) : selectedValue;
10466
+ handleChange(rowPath, {
10467
+ [num]: {
10468
+ [schemaName]: coerced
10469
+ }
10470
+ });
10471
+ },
10472
+ width: "100%",
10473
+ ariaLabel: schemaName,
10474
+ error: !!(error === null || error === void 0 ? void 0 : error.message),
10475
+ children: [!(required === null || required === void 0 ? void 0 : required.includes(schemaName)) && jsx(GoADropdownItem, {
10476
+ value: "",
10477
+ label: `-- Select ${convertToSentenceCase(schemaName)} --`
10478
+ }), dataObject.enum.map(opt => jsx(GoADropdownItem, {
10479
+ value: String(opt),
10480
+ label: String(opt)
10481
+ }, String(opt)))]
10482
+ }) : dataObject.type === 'number' || dataObject.type === 'string' && !dataObject.enum ? jsx(GoAInput, {
10483
+ error: (error === null || error === void 0 ? void 0 : error.message.length) > 0,
10484
+ type: dataObject.type === 'number' ? 'number' : 'text',
10485
+ id: schemaName,
10486
+ name: schemaName,
10487
+ value: currentData,
10488
+ testId: `#/properties/${schemaName}-input-${i}`,
10489
+ onChange: (name, value) => {
10490
+ handleChange(rowPath, {
10491
+ [num]: {
10492
+ [name]: dataObject.type === 'number' ? parseInt(value) : value
10493
+ }
10494
+ });
10495
+ },
10496
+ ariaLabel: schemaName,
10497
+ width: "100%"
10498
+ }) : jsx(GoACallout, {
10499
+ type: "important",
10500
+ size: "medium",
10501
+ testId: "form-support-callout",
10502
+ heading: "Not supported",
10503
+ children: "Only string, number, and enum are supported inside arrays"
10436
10504
  })
10437
10505
  })
10438
10506
  }, ix);
10439
- }
10440
- return jsx("td", {
10441
- children: jsx(GoAFormItem, {
10442
- error: (_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : '',
10443
- mb: errorRow && !error && '2xl' || 'xs',
10444
- children: dataObject.enum ? jsxs(GoADropdown, {
10445
- id: schemaName,
10446
- name: schemaName,
10447
- value: currentData != null ? String(currentData) : '',
10448
- testId: `#/properties/${schemaName}-select-${i}`,
10449
- onChange: (name, value) => {
10450
- const selectedValue = Array.isArray(value) ? value[0] : value;
10451
- const coerced = dataObject.type === 'number' && selectedValue !== '' ? Number(selectedValue) : selectedValue;
10452
- handleChange(rowPath, {
10453
- [num]: {
10454
- [schemaName]: coerced
10455
- }
10456
- });
10457
- },
10458
- width: "100%",
10459
- ariaLabel: schemaName,
10460
- error: !!(error === null || error === void 0 ? void 0 : error.message),
10461
- children: [!(required === null || required === void 0 ? void 0 : required.includes(schemaName)) && jsx(GoADropdownItem, {
10462
- value: "",
10463
- label: `-- Select ${convertToSentenceCase(schemaName)} --`
10464
- }), dataObject.enum.map(opt => jsx(GoADropdownItem, {
10465
- value: String(opt),
10466
- label: String(opt)
10467
- }, String(opt)))]
10468
- }) : dataObject.type === 'number' || dataObject.type === 'string' && !dataObject.enum ? jsx(GoAInput, {
10469
- error: (error === null || error === void 0 ? void 0 : error.message.length) > 0,
10470
- type: dataObject.type === 'number' ? 'number' : 'text',
10471
- id: schemaName,
10472
- name: schemaName,
10473
- value: currentData,
10474
- testId: `#/properties/${schemaName}-input-${i}`,
10475
- onChange: (name, value) => {
10476
- handleChange(rowPath, {
10477
- [num]: {
10478
- [name]: dataObject.type === 'number' ? parseInt(value) : value
10479
- }
10480
- });
10481
- },
10482
- ariaLabel: schemaName,
10483
- width: "100%"
10484
- }) : jsx(GoACallout, {
10485
- type: "important",
10486
- size: "medium",
10487
- testId: "form-support-callout",
10488
- heading: "Not supported",
10489
- children: "Only string, number, and enum are supported inside arrays"
10507
+ }), !isInReview && jsx("td", {
10508
+ style: {
10509
+ alignContent: 'baseLine',
10510
+ paddingTop: '18px'
10511
+ },
10512
+ children: jsx("div", {
10513
+ "aria-hidden": "true",
10514
+ children: jsx(GoAIconButton, {
10515
+ icon: "trash",
10516
+ title: "trash button",
10517
+ testId: "trash-icon-button",
10518
+ "aria-label": `remove-element-${num}`,
10519
+ onClick: () => openDeleteDialog(num)
10490
10520
  })
10491
10521
  })
10492
- }, ix);
10493
- }), !isInReview && jsx("td", {
10494
- style: {
10495
- alignContent: 'baseLine',
10496
- paddingTop: '18px'
10497
- },
10498
- children: jsx("div", {
10499
- "aria-hidden": "true",
10500
- children: jsx(GoAIconButton, {
10501
- icon: "trash",
10502
- title: "trash button",
10503
- testId: "trash-icon-button",
10504
- "aria-label": `remove-element-${num}`,
10505
- onClick: () => openDeleteDialog(num)
10506
- })
10507
- })
10508
- })]
10509
- }, `${rowPath}-${i}-${num}`);
10510
- })
10511
- })]
10522
+ })]
10523
+ }, `${rowPath}-${i}-${num}`);
10524
+ })
10525
+ })]
10526
+ })
10512
10527
  }), hasAnyErrors && isInReview && jsx(GoAFormItem, {
10513
10528
  error: `There are validation errors for '${capitalizeFirstLetter(rowPath)}'`
10514
10529
  })]
@@ -11061,6 +11076,57 @@ const NonEmptyRowComponent = ({
11061
11076
  }) : null
11062
11077
  }, childPath);
11063
11078
  };
11079
+ const MainItemComponent = ({
11080
+ childPath,
11081
+ rowIndex,
11082
+ openDeleteDialog,
11083
+ selectCurrentTab,
11084
+ enabled,
11085
+ currentTab,
11086
+ current,
11087
+ setCurrentListPage,
11088
+ rowData
11089
+ }) => {
11090
+ const displayName = Object.keys(rowData !== null && rowData !== void 0 ? rowData : {}).length === 0 ? 'No data' : Object.values(rowData || {}).join(', ');
11091
+ return jsx(SideMenuItem, {
11092
+ onClick: () => selectCurrentTab(rowIndex),
11093
+ onKeyDown: e => {
11094
+ if (e.key === 'ArrowRight') {
11095
+ e.preventDefault();
11096
+ if (current) {
11097
+ const goa = current === null || current === void 0 ? void 0 : current.querySelector('goa-input, goa-button');
11098
+ if (goa === null || goa === void 0 ? void 0 : goa.shadowRoot) {
11099
+ const internal = goa.shadowRoot.querySelector('input, button');
11100
+ internal === null || internal === void 0 ? void 0 : internal.focus();
11101
+ selectCurrentTab(rowIndex);
11102
+ }
11103
+ }
11104
+ }
11105
+ },
11106
+ children: jsxs(RowFlexMenu, {
11107
+ tabIndex: 0,
11108
+ children: [jsx(TabName, {
11109
+ children: displayName
11110
+ }), enabled ? jsx(Trash, {
11111
+ children: jsx(GoAIconButton, {
11112
+ disabled: !enabled,
11113
+ icon: "trash",
11114
+ title: 'remove',
11115
+ testId: "remove the details",
11116
+ onClick: () => openDeleteDialog(childPath, rowIndex, displayName)
11117
+ })
11118
+ }) : null, jsx(IconPadding, {
11119
+ children: jsx(GoAIconButton, {
11120
+ disabled: !enabled,
11121
+ icon: "create",
11122
+ title: 'edit',
11123
+ testId: "edit button",
11124
+ onClick: () => setCurrentListPage(currentTab + 1)
11125
+ })
11126
+ })]
11127
+ })
11128
+ });
11129
+ };
11064
11130
  const MainTab = ({
11065
11131
  childPath,
11066
11132
  rowIndex,
@@ -11068,7 +11134,6 @@ const MainTab = ({
11068
11134
  selectCurrentTab,
11069
11135
  enabled,
11070
11136
  currentTab,
11071
- name,
11072
11137
  current,
11073
11138
  setCurrentListPage
11074
11139
  }) => {
@@ -11082,48 +11147,35 @@ const MainTab = ({
11082
11147
  const rowErrors = (_a = core === null || core === void 0 ? void 0 : core.errors) === null || _a === void 0 ? void 0 : _a.filter(e => {
11083
11148
  const base = `/${childPath.replace(/\./g, '/')}`;
11084
11149
  return e.instancePath === base || e.instancePath.startsWith(base + '/');
11085
- }).map(error => error === null || error === void 0 ? void 0 : error.message);
11150
+ }).map(e => {
11151
+ var _a, _b;
11152
+ return ((_b = (_a = e === null || e === void 0 ? void 0 : e.message) === null || _a === void 0 ? void 0 : _a.trim) === null || _b === void 0 ? void 0 : _b.call(_a)) || '';
11153
+ }).filter(msg => msg.length > 0).map((msg, index, arr) => `${msg}${index < arr.length - 1 ? ', ' : ''}`);
11086
11154
  return jsx("div", {
11087
- children: jsx(GoAFormItem, {
11088
- error: (rowErrors === null || rowErrors === void 0 ? void 0 : rowErrors.length) ? rowErrors : undefined,
11089
- children: jsx(SideMenuItem, {
11090
- onClick: () => selectCurrentTab(rowIndex),
11091
- onKeyDown: e => {
11092
- if (e.key === 'ArrowRight') {
11093
- e.preventDefault();
11094
- if (current) {
11095
- const goa = current === null || current === void 0 ? void 0 : current.querySelector('goa-input, goa-button');
11096
- if (goa === null || goa === void 0 ? void 0 : goa.shadowRoot) {
11097
- const internal = goa.shadowRoot.querySelector('input, button');
11098
- internal === null || internal === void 0 ? void 0 : internal.focus();
11099
- selectCurrentTab(rowIndex);
11100
- }
11101
- }
11102
- }
11103
- },
11104
- children: jsxs(RowFlexMenu, {
11105
- tabIndex: 0,
11106
- children: [jsxs(TabData, {
11107
- children: [Object.keys(rowData !== null && rowData !== void 0 ? rowData : {}).length === 0 && 'No data', " ", Object.values(rowData).join(', ')]
11108
- }), enabled ? jsx(Trash, {
11109
- children: jsx(GoAIconButton, {
11110
- disabled: !enabled,
11111
- icon: "trash",
11112
- title: 'remove',
11113
- testId: "remove the details",
11114
- onClick: () => openDeleteDialog(childPath, rowIndex, name)
11115
- })
11116
- }) : null, jsx(IconPadding, {
11117
- children: jsx(GoAIconButton, {
11118
- disabled: !enabled,
11119
- icon: "create",
11120
- title: 'edit',
11121
- testId: "edit button",
11122
- onClick: () => setCurrentListPage(currentTab + 1)
11123
- })
11124
- })]
11125
- })
11155
+ "data-testid": `object-array-main-item-${rowIndex}`,
11156
+ children: (rowErrors === null || rowErrors === void 0 ? void 0 : rowErrors.length) ? jsx(GoAFormItem, {
11157
+ error: (rowErrors === null || rowErrors === void 0 ? void 0 : rowErrors.length) ? rowErrors : null,
11158
+ children: jsx(MainItemComponent, {
11159
+ rowData: rowData,
11160
+ childPath: childPath,
11161
+ rowIndex: rowIndex,
11162
+ openDeleteDialog: openDeleteDialog,
11163
+ selectCurrentTab: selectCurrentTab,
11164
+ enabled: enabled,
11165
+ currentTab: currentTab,
11166
+ current: current,
11167
+ setCurrentListPage: setCurrentListPage
11126
11168
  })
11169
+ }) : jsx(MainItemComponent, {
11170
+ rowData: rowData,
11171
+ childPath: childPath,
11172
+ rowIndex: rowIndex,
11173
+ openDeleteDialog: openDeleteDialog,
11174
+ selectCurrentTab: selectCurrentTab,
11175
+ enabled: enabled,
11176
+ currentTab: currentTab,
11177
+ current: current,
11178
+ setCurrentListPage: setCurrentListPage
11127
11179
  })
11128
11180
  }, childPath);
11129
11181
  };
@@ -11177,10 +11229,6 @@ const ObjectArrayList = ({
11177
11229
  const selectCurrentTab = index => {
11178
11230
  setCurrentIndex(index);
11179
11231
  };
11180
- (() => {
11181
- const str = (appliedUiSchemaOptions === null || appliedUiSchemaOptions === void 0 ? void 0 : appliedUiSchemaOptions.itemLabel) ? `${appliedUiSchemaOptions.itemLabel}` : `${path}`;
11182
- return str.charAt(0).toUpperCase() + str.slice(1);
11183
- })();
11184
11232
  return jsx(ListContainer, {
11185
11233
  children: jsxs(RowFlex, {
11186
11234
  children: [currentListPage === 0 && jsx(FlexTabs, {
@@ -11189,12 +11237,10 @@ const ObjectArrayList = ({
11189
11237
  },
11190
11238
  children: range(data).map(index => {
11191
11239
  const childPath = Paths.compose(path, `${index}`);
11192
- const name = (appliedUiSchemaOptions === null || appliedUiSchemaOptions === void 0 ? void 0 : appliedUiSchemaOptions.itemLabel) ? `${pluralize.singular(appliedUiSchemaOptions === null || appliedUiSchemaOptions === void 0 ? void 0 : appliedUiSchemaOptions.itemLabel)} ${index + 1}` : `${pluralize.singular(path)} ${index + 1}`;
11193
11240
  return jsx(MainTab, {
11194
11241
  childPath: childPath,
11195
11242
  rowIndex: index,
11196
11243
  currentTab: currentIndex,
11197
- name: name,
11198
11244
  openDeleteDialog: openDeleteDialog,
11199
11245
  selectCurrentTab: selectCurrentTab,
11200
11246
  enabled: enabled,
@@ -13120,32 +13166,42 @@ const PhoneNumberWithTypeReviewControl = props => {
13120
13166
  };
13121
13167
  const GoAInputBasePhoneNumberWithTypeReviewControl = withJsonFormsAllOfProps(PhoneNumberWithTypeReviewControl);
13122
13168
 
13169
+ /**
13170
+ * Escape for use in RegExp
13171
+ */
13123
13172
  function escapeRegExp(s) {
13124
13173
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
13125
13174
  }
13175
+ /**
13176
+ * Resolve a JSON Pointer–style scope like "#/properties/x" or "#/properties/arr/c3"
13177
+ */
13126
13178
  function resolveScope(scope, data) {
13127
13179
  if (!scope || typeof scope !== 'string') return undefined;
13180
+ // normalize: strip "#/" and optional "properties/"
13128
13181
  const cleaned = scope.replace(/^#\/(properties\/)?/, '');
13129
13182
  const parts = cleaned.split('/').filter(Boolean);
13130
13183
  let cur = data;
13131
- for (const part of parts) {
13132
- if (cur == null) return undefined;
13133
- if (Array.isArray(cur) && /^\d+$/.test(part)) {
13134
- cur = cur[Number(part)];
13135
- } else if (typeof cur === 'object') {
13136
- if (part === 'properties') continue;
13137
- cur = cur[part];
13138
- } else {
13139
- return undefined;
13140
- }
13184
+ for (const p of parts) {
13185
+ if (cur == null || typeof cur !== 'object') return undefined;
13186
+ cur = cur[p];
13141
13187
  }
13142
13188
  return cur;
13143
13189
  }
13144
- function evaluateSum(scope, data) {
13190
+ /**
13191
+ * SUM(#/properties/arr/c3) helper
13192
+ */
13193
+ function evaluateSum(scope, data, opts) {
13145
13194
  if (!scope || typeof scope !== 'string') {
13146
13195
  return {
13147
13196
  value: undefined,
13148
- error: 'SUM() requires a JSON pointer argument.'
13197
+ error: 'SUM requires a scope argument.'
13198
+ };
13199
+ }
13200
+ const normalized = scope.replace(/^#\/(properties\/)?/, '#/properties/');
13201
+ if ((opts === null || opts === void 0 ? void 0 : opts.knownScopes) && !opts.knownScopes.includes(normalized)) {
13202
+ return {
13203
+ value: undefined,
13204
+ error: `Invalid scope(s): ${normalized}`
13149
13205
  };
13150
13206
  }
13151
13207
  const cleaned = scope.replace(/^#\/(properties\/)?/, '');
@@ -13153,83 +13209,62 @@ function evaluateSum(scope, data) {
13153
13209
  if (parts.length < 2) {
13154
13210
  return {
13155
13211
  value: undefined,
13156
- error: `SUM() pointer "${scope}" must include an array and field name.`
13212
+ error: 'SUM requires array/column path like #/properties/arr/c3'
13157
13213
  };
13158
13214
  }
13159
- const fieldKey = parts[parts.length - 1];
13215
+ const colKey = parts[parts.length - 1];
13160
13216
  const arrPath = parts.slice(0, -1);
13161
13217
  let cur = data;
13162
- for (const segment of arrPath) {
13163
- if (cur == null) {
13164
- cur = undefined;
13165
- break;
13166
- }
13167
- if (Array.isArray(cur) && /^\d+$/.test(segment)) {
13168
- cur = cur[Number(segment)];
13169
- } else if (typeof cur === 'object') {
13170
- if (segment === 'properties') continue;
13171
- cur = cur[segment];
13172
- } else {
13218
+ for (const p of arrPath) {
13219
+ if (cur == null || typeof cur !== 'object') {
13173
13220
  cur = undefined;
13174
13221
  break;
13175
13222
  }
13223
+ cur = cur[p];
13176
13224
  }
13177
- if (cur == null) {
13225
+ if (cur === undefined) {
13178
13226
  return {
13179
13227
  value: undefined,
13180
- error: `Please provide values for: ${scope}`
13228
+ error: undefined
13181
13229
  };
13182
13230
  }
13183
13231
  if (!Array.isArray(cur)) {
13184
13232
  return {
13185
13233
  value: undefined,
13186
- error: `SUM() pointer "${scope}" does not resolve to an array.`
13234
+ error: `Expected an array at "#/properties/${arrPath.join('/')}"`
13187
13235
  };
13188
13236
  }
13189
- const missingIndices = [];
13190
- const invalidIndices = [];
13191
13237
  let sum = 0;
13192
- for (let i = 0; i < cur.length; i++) {
13193
- const row = cur[i];
13194
- if (row == null || typeof row !== 'object') {
13195
- missingIndices.push(i);
13196
- continue;
13197
- }
13198
- const v = row[fieldKey];
13199
- if (v === undefined || v === null || v === '') {
13200
- missingIndices.push(i);
13201
- } else if (typeof v !== 'number' || Number.isNaN(v)) {
13202
- invalidIndices.push(i);
13203
- } else {
13238
+ let anyValue = false;
13239
+ let anyMissing = false;
13240
+ for (const row of cur) {
13241
+ if (row == null || typeof row !== 'object') continue;
13242
+ const v = row[colKey];
13243
+ if (typeof v === 'number' && Number.isFinite(v)) {
13244
+ anyValue = true;
13204
13245
  sum += v;
13246
+ } else if (v !== undefined && v !== null) {
13247
+ anyMissing = true;
13205
13248
  }
13206
13249
  }
13207
- if (invalidIndices.length > 0) {
13250
+ if (!anyValue && !anyMissing) {
13208
13251
  return {
13209
13252
  value: undefined,
13210
- error: `Expected numeric values for: ${scope} at rows [${invalidIndices.join(', ')}]`
13253
+ error: undefined
13211
13254
  };
13212
13255
  }
13213
- if (missingIndices.length === cur.length) {
13256
+ if (anyMissing) {
13214
13257
  return {
13215
13258
  value: undefined,
13216
- error: `Please provide values for: ${scope}`
13259
+ error: `Please provide values for: ${normalized}`
13217
13260
  };
13218
13261
  }
13219
13262
  return {
13220
13263
  value: sum,
13221
- error: missingIndices.length ? `Some rows are missing values for: ${scope}` : undefined
13264
+ error: undefined
13222
13265
  };
13223
13266
  }
13224
- /**
13225
- * General expression evaluation.
13226
- * - Supports SUM(#/properties/arr/c3)
13227
- * - Supports arithmetic with JSON pointers:
13228
- * "#/properties/x * #/properties/y + #/properties/z"
13229
- *
13230
- * Returns { value, error } and NEVER throws.
13231
- */
13232
- function evaluateExpression(expression, data) {
13267
+ function evaluateExpression(expression, data, opts) {
13233
13268
  if (!expression || typeof expression !== 'string') {
13234
13269
  return {
13235
13270
  value: undefined,
@@ -13237,66 +13272,63 @@ function evaluateExpression(expression, data) {
13237
13272
  };
13238
13273
  }
13239
13274
  const trimmed = expression.trim();
13240
- if (!trimmed) return {
13241
- value: undefined,
13242
- error: undefined
13243
- };
13275
+ if (!trimmed) {
13276
+ return {
13277
+ value: undefined,
13278
+ error: undefined
13279
+ };
13280
+ }
13244
13281
  const sumMatch = trimmed.match(/^SUM\(\s*['"]?(.+?)['"]?\s*\)$/i);
13245
13282
  if (sumMatch) {
13246
- const pointer = sumMatch[1];
13247
- return evaluateSum(pointer, data);
13283
+ const sumScope = sumMatch[1];
13284
+ return evaluateSum(sumScope, data, opts);
13248
13285
  }
13249
- const scopeRegex = /#\/(?:properties\/)?[^\s"')]+/g;
13286
+ const scopeRegex = /#\/(?:properties\/)?[^\s"'()]+/g;
13250
13287
  const matches = trimmed.match(scopeRegex) || [];
13251
13288
  const uniqueScopes = Array.from(new Set(matches));
13252
- let exprForParse = trimmed;
13253
- const scopeToVar = new Map();
13254
- uniqueScopes.forEach((scope, index) => {
13255
- const varName = `v${index}`;
13256
- scopeToVar.set(scope, varName);
13257
- const pattern = new RegExp(`['"]?${escapeRegExp(scope)}['"]?`, 'g');
13258
- exprForParse = exprForParse.replace(pattern, varName);
13259
- });
13260
- let parsed;
13261
- try {
13262
- const parser = new Parser();
13263
- parsed = parser.parse(exprForParse);
13264
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
13265
- } catch (e) {
13266
- return {
13267
- value: undefined,
13268
- error: 'Invalid expression syntax'
13269
- };
13289
+ const normalizedScopes = uniqueScopes.map(s => s.replace(/^#\/(properties\/)?/, '#/properties/'));
13290
+ if ((opts === null || opts === void 0 ? void 0 : opts.knownScopes) && opts.knownScopes.length) {
13291
+ const invalidScopes = normalizedScopes.filter(s => !opts.knownScopes.includes(s));
13292
+ if (invalidScopes.length > 0) {
13293
+ return {
13294
+ value: undefined,
13295
+ error: `Invalid scope(s): ${invalidScopes.join(', ')}`
13296
+ };
13297
+ }
13270
13298
  }
13271
13299
  const vars = {};
13300
+ let expr = trimmed;
13272
13301
  const missingScopes = [];
13273
- const invalidTypeScopes = [];
13274
- for (const scope of uniqueScopes) {
13302
+ let anyValuePresent = false;
13303
+ uniqueScopes.forEach((scope, idx) => {
13304
+ const normalized = scope.replace(/^#\/(properties\/)?/, '#/properties/');
13275
13305
  const val = resolveScope(scope, data);
13276
- if (val === undefined || val === null || val === '') {
13277
- missingScopes.push(scope);
13278
- continue;
13279
- }
13280
- if (typeof val !== 'number' || Number.isNaN(val)) {
13281
- invalidTypeScopes.push(scope);
13282
- continue;
13306
+ if (typeof val === 'number' && Number.isFinite(val)) {
13307
+ anyValuePresent = true;
13308
+ const varName = `v${idx}`;
13309
+ vars[varName] = val;
13310
+ const pattern = new RegExp(`['"]?${escapeRegExp(scope)}['"]?`, 'g');
13311
+ expr = expr.replace(pattern, varName);
13312
+ } else {
13313
+ missingScopes.push(normalized);
13283
13314
  }
13284
- const varName = scopeToVar.get(scope);
13285
- vars[varName] = val;
13286
- }
13287
- if (invalidTypeScopes.length > 0) {
13315
+ });
13316
+ if (!anyValuePresent && missingScopes.length === normalizedScopes.length) {
13288
13317
  return {
13289
13318
  value: undefined,
13290
- error: `Expected numeric values for: ${invalidTypeScopes.join(', ')}`
13319
+ error: undefined
13291
13320
  };
13292
13321
  }
13293
13322
  if (missingScopes.length > 0) {
13323
+ const uniqMissing = Array.from(new Set(missingScopes));
13294
13324
  return {
13295
13325
  value: undefined,
13296
- error: `Please provide values for: ${missingScopes.join(', ')}`
13326
+ error: `Please provide values for: ${uniqMissing.join(', ')}`
13297
13327
  };
13298
13328
  }
13299
13329
  try {
13330
+ const parser = new Parser();
13331
+ const parsed = parser.parse(expr);
13300
13332
  const result = parsed.evaluate(vars);
13301
13333
  if (typeof result === 'number' && Number.isFinite(result)) {
13302
13334
  return {
@@ -13306,15 +13338,30 @@ function evaluateExpression(expression, data) {
13306
13338
  }
13307
13339
  return {
13308
13340
  value: undefined,
13309
- error: 'Expression did not produce a numeric result'
13341
+ error: 'Invalid expression result (not a finite number).'
13310
13342
  };
13311
13343
  } catch (_a) {
13312
13344
  return {
13313
13345
  value: undefined,
13314
- error: 'Error while evaluating expression'
13346
+ error: 'Invalid expression syntax'
13315
13347
  };
13316
13348
  }
13317
13349
  }
13350
+ function collectScopes(schema, base = '#') {
13351
+ if (!schema || typeof schema !== 'object') return [];
13352
+ const scopes = [];
13353
+ if (schema.type === 'object' && schema.properties && typeof schema.properties === 'object') {
13354
+ Object.entries(schema.properties).forEach(([key, subschema]) => {
13355
+ const here = base === '#' ? `#/properties/${key}` : `${base}/${key}`;
13356
+ scopes.push(here);
13357
+ scopes.push(...collectScopes(subschema, here));
13358
+ });
13359
+ }
13360
+ if (schema.type === 'array' && schema.items) {
13361
+ scopes.push(...collectScopes(schema.items, base));
13362
+ }
13363
+ return Array.from(new Set(scopes));
13364
+ }
13318
13365
 
13319
13366
  const GoACalculation = props => {
13320
13367
  var _a;
@@ -13326,33 +13373,36 @@ const GoACalculation = props => {
13326
13373
  visible,
13327
13374
  handleChange
13328
13375
  } = props;
13329
- const label = typeof (uischema === null || uischema === void 0 ? void 0 : uischema.label) === 'string' ? uischema.label : undefined;
13330
- const expression = schema === null || schema === void 0 ? void 0 : schema.description;
13331
13376
  const {
13332
13377
  core
13333
13378
  } = useJsonForms();
13379
+ const rootSchema = core === null || core === void 0 ? void 0 : core.schema;
13334
13380
  const rootData = (_a = core === null || core === void 0 ? void 0 : core.data) !== null && _a !== void 0 ? _a : {};
13381
+ const label = typeof (uischema === null || uischema === void 0 ? void 0 : uischema.label) === 'string' ? uischema.label : undefined;
13382
+ const expression = schema === null || schema === void 0 ? void 0 : schema.description;
13383
+ const knownScopes = useMemo(() => collectScopes(rootSchema), [rootSchema]);
13335
13384
  const [hasInteracted, setHasInteracted] = useState(false);
13336
- const prevDataRef = useRef(rootData);
13385
+ const initialSnapshot = useRef(JSON.stringify(rootData));
13337
13386
  useEffect(() => {
13338
- setHasInteracted(was => was ? true : true);
13339
- }, [rootData]);
13340
- useEffect(() => {
13341
- if (prevDataRef.current !== rootData) {
13387
+ if (hasInteracted) return;
13388
+ const now = JSON.stringify(rootData);
13389
+ if (now !== initialSnapshot.current) {
13342
13390
  setHasInteracted(true);
13343
- prevDataRef.current = rootData;
13344
13391
  }
13345
- }, [rootData]);
13392
+ }, [rootData, hasInteracted]);
13346
13393
  const {
13347
13394
  value: computedValue,
13348
13395
  error
13349
- } = evaluateExpression(expression, rootData);
13396
+ } = evaluateExpression(expression, rootData, {
13397
+ knownScopes
13398
+ });
13350
13399
  useEffect(() => {
13351
13400
  if (computedValue !== undefined && typeof handleChange === 'function' && path) {
13352
13401
  handleChange(path, computedValue);
13353
13402
  }
13354
13403
  }, [computedValue, handleChange, path]);
13355
- const showError = hasInteracted && !!error;
13404
+ const isConfigError = !!error && (error.toLowerCase().includes('invalid scope') || error.toLowerCase().includes('expression syntax'));
13405
+ const showError = !!error && (isConfigError || hasInteracted);
13356
13406
  return jsx(Visible, {
13357
13407
  visible: visible,
13358
13408
  children: jsx(GoAFormItem, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/jsonforms-components",
3
- "version": "2.38.2",
3
+ "version": "2.38.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,15 +1,19 @@
1
- export interface EvaluationResult {
1
+ import { JsonSchema } from '@jsonforms/core';
2
+ export interface EvalResult {
2
3
  value?: number;
3
4
  error?: string;
4
5
  }
6
+ /**
7
+ * Resolve a JSON Pointer–style scope like "#/properties/x" or "#/properties/arr/c3"
8
+ */
5
9
  export declare function resolveScope(scope: string, data: unknown): unknown;
6
- export declare function evaluateSum(scope: string | undefined, data: unknown): EvaluationResult;
7
10
  /**
8
- * General expression evaluation.
9
- * - Supports SUM(#/properties/arr/c3)
10
- * - Supports arithmetic with JSON pointers:
11
- * "#/properties/x * #/properties/y + #/properties/z"
12
- *
13
- * Returns { value, error } and NEVER throws.
11
+ * SUM(#/properties/arr/c3) helper
14
12
  */
15
- export declare function evaluateExpression(expression: string | undefined, data: unknown): EvaluationResult;
13
+ export declare function evaluateSum(scope: string, data: unknown, opts?: {
14
+ knownScopes?: string[];
15
+ }): EvalResult;
16
+ export declare function evaluateExpression(expression: string | undefined, data: unknown, opts?: {
17
+ knownScopes?: string[];
18
+ }): EvalResult;
19
+ export declare function collectScopes(schema: JsonSchema | undefined, base?: string): string[];
@@ -10,7 +10,7 @@ export declare const RowFlex: import("styled-components/dist/types").IStyledComp
10
10
  export declare const RowFlexMenu: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
11
11
  export declare const FlexTabs: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
12
12
  export declare const FlexForm: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
13
- export declare const TabData: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
13
+ export declare const TabName: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
14
14
  export declare const Trash: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
15
15
  export declare const ListContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
16
16
  export declare const IconPadding: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
@@ -22,3 +22,4 @@ export declare const ListWithDetailWarningIconDiv: import("styled-components/dis
22
22
  export declare const ObjectArrayRequiredTextLabel: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, never>> & string;
23
23
  export declare const HasErrorLabel: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
24
24
  export declare const HilightCellWarning: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
25
+ export declare const FixTableHeaderAlignment: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;