@ukhomeoffice/cop-react-form-renderer 7.2.0 → 7.3.1

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.
@@ -32,6 +32,7 @@ const DEFAULT_MARGIN_BOTTOM = exports.DEFAULT_MARGIN_BOTTOM = 9;
32
32
  const CheckYourAnswers = _ref => {
33
33
  let {
34
34
  title,
35
+ titleSize,
35
36
  pages: _pages,
36
37
  actions,
37
38
  onAction,
@@ -145,7 +146,8 @@ const CheckYourAnswers = _ref => {
145
146
  };
146
147
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
147
148
  className: DEFAULT_CLASS,
148
- children: [title && !hide_title && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.LargeHeading, {
149
+ children: [title && !hide_title && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.Heading, {
150
+ size: titleSize,
149
151
  children: title
150
152
  }, 'heading'), errors && errors.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.ErrorSummary, {
151
153
  errors: getDedupedErrors()
@@ -225,6 +227,7 @@ CheckYourAnswers.propTypes = {
225
227
  })),
226
228
  summaryListClassModifiers: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
227
229
  title: _propTypes.default.string,
230
+ titleSize: _propTypes.default.string,
228
231
  type: _propTypes.default.string,
229
232
  hideBlankRows: _propTypes.default.bool,
230
233
  optionalFieldPlaceholder: _propTypes.default.string
@@ -240,6 +243,7 @@ CheckYourAnswers.defaultProps = {
240
243
  sections: [],
241
244
  summaryListClassModifiers: null,
242
245
  title: DEFAULT_TITLE,
246
+ titleSize: 'l',
243
247
  type: null,
244
248
  hideBlankRows: false,
245
249
  optionalFieldPlaceholder: null
@@ -100,6 +100,7 @@ const RenderListView = _ref => {
100
100
  className: classes('content'),
101
101
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("dl", {
102
102
  className: listClass(),
103
+ role: "list",
103
104
  children: masterPage === null || masterPage === void 0 || (_masterPage$childPage = masterPage.childPages) === null || _masterPage$childPage === void 0 ? void 0 : _masterPage$childPage.flatMap(childPage => {
104
105
  var _childPage$summaryLay;
105
106
  const elevatedComponents = childPage.components.map(component => _utils.default.Component.elevateNested([component], entryData)).flat().filter(Boolean);
@@ -61,6 +61,7 @@ const SummaryCardDetails = _ref => {
61
61
  '--column': columnIndex + 1,
62
62
  '--row': rowIndex
63
63
  },
64
+ role: "list",
64
65
  children: containerRows.map(subComponent => {
65
66
  var _entryData$component$;
66
67
  // Put value for current subcomponent at top level
@@ -85,6 +86,7 @@ const SummaryCardDetails = _ref => {
85
86
  '--column': columnIndex + 1,
86
87
  '--row': rowIndex
87
88
  },
89
+ role: "list",
88
90
  children: collectionRows.map(subComponent => {
89
91
  var _entryData$component$2;
90
92
  // Put value for current subComponent at the top level
@@ -117,6 +119,7 @@ const SummaryCardDetails = _ref => {
117
119
  '--column': columnIndex + 1,
118
120
  '--row': rowIndex
119
121
  },
122
+ role: "list",
120
123
  children: (0, _getSummaryListRowForDetails.default)(childPage, component, classes, entryData, optionalFieldPlaceholder)
121
124
  }, fieldId);
122
125
  });
@@ -71,10 +71,12 @@ const Container = _ref => {
71
71
  };
72
72
  const classes = _utils.default.classBuilder(DEFAULT_CLASS, [], container.className);
73
73
  const cleanedAttrs = _copReactComponents.Utils.cleanHtmlAttributes(attrs);
74
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", _objectSpread(_objectSpread({}, cleanedAttrs), {}, {
74
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, cleanedAttrs), {}, {
75
75
  className: classes(),
76
76
  id: container.id,
77
- children: container.components && container.components.filter(shouldShow).map((component, index) => {
77
+ children: [container.title && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.MediumHeading, {
78
+ children: container.title
79
+ }), container.components && container.components.filter(shouldShow).map((component, index) => {
78
80
  const defaultValue = component.type === _models.ComponentTypes.FILE ? {} : '';
79
81
  const val = value ? value[component.fieldId] : defaultValue;
80
82
  const fullPath = "".concat(container.full_path || container.fieldId, ".").concat(component.fieldId);
@@ -89,7 +91,7 @@ const Container = _ref => {
89
91
  onChange: onComponentChange,
90
92
  onTopLevelChange: onTopLevelChange
91
93
  }), index);
92
- })
94
+ })]
93
95
  }));
94
96
  };
95
97
  Container.propTypes = {
@@ -102,7 +104,8 @@ Container.propTypes = {
102
104
  fieldId: _propTypes.default.string,
103
105
  full_path: _propTypes.default.string,
104
106
  id: _propTypes.default.string,
105
- readonly: _propTypes.default.bool
107
+ readonly: _propTypes.default.bool,
108
+ title: _propTypes.default.string
106
109
  }).isRequired,
107
110
  formData: _propTypes.default.shape({}),
108
111
  fullPath: _propTypes.default.string,
@@ -407,4 +407,49 @@ describe('components.FormComponent.Container', () => {
407
407
  expect(input2.id).toEqual("".concat(ID, ".").concat(TEXT_ID, "Two"));
408
408
  expect(input2.value).toEqual('blue');
409
409
  });
410
+ it('should render a container component appropriately with a title', async () => {
411
+ const CONTAINER = {
412
+ id: ID,
413
+ fieldId: ID,
414
+ title: "some title",
415
+ type: _models.ComponentTypes.CONTAINER,
416
+ components: [TEXT_COMPONENT]
417
+ };
418
+ const {
419
+ container
420
+ } = (0, _setupTests.renderWithValidation)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_FormComponent.default, {
421
+ component: CONTAINER,
422
+ value: FORM_DATA[ID],
423
+ formData: FORM_DATA
424
+ }));
425
+
426
+ // Check the container itself.
427
+ const c = container.childNodes[0];
428
+ expect(c.tagName).toEqual('DIV');
429
+ expect(c.classList).toContain(_Container.DEFAULT_CLASS);
430
+
431
+ // Check container header.
432
+ const containerHeader = c.childNodes[0];
433
+ expect(containerHeader.tagName).toEqual('H2');
434
+ expect(containerHeader.textContent).toEqual('some title');
435
+
436
+ // And now check the single text component within it.
437
+ const formGroup = c.childNodes[1];
438
+ expect(formGroup.tagName).toEqual('DIV');
439
+ expect(formGroup.classList).toContain('govuk-form-group');
440
+ const label = formGroup.childNodes[0];
441
+ expect(label.tagName).toEqual('LABEL');
442
+ expect(label.classList).toContain('govuk-label');
443
+ expect(label.textContent).toEqual("".concat(TEXT_COMPONENT.label, " (optional)"));
444
+ expect(label.getAttribute('for')).toEqual("".concat(ID, ".").concat(TEXT_ID));
445
+ const hint = formGroup.childNodes[1];
446
+ expect(hint.tagName).toEqual('DIV');
447
+ expect(hint.classList).toContain('govuk-hint');
448
+ expect(hint.textContent).toEqual(TEXT_COMPONENT.hint);
449
+ const input = formGroup.childNodes[2];
450
+ expect(input.tagName).toEqual('INPUT');
451
+ expect(input.classList).toContain('govuk-input');
452
+ expect(input.id).toEqual("".concat(ID, ".").concat(TEXT_ID));
453
+ expect(input.value).toEqual(TEXT_VALUE);
454
+ });
410
455
  });
@@ -110,6 +110,9 @@ const FormComponent = _ref => {
110
110
  value: value || _utils.default.Component.defaultValue(component, formData),
111
111
  formData: formData
112
112
  }));
113
+ if (component.fieldset) {
114
+ container = (0, _wrapInFormGroup.default)(component, container);
115
+ }
113
116
  if (component.additionalValidation) {
114
117
  container = (0, _wrapInFormGroup.default)(_objectSpread(_objectSpread({}, component), (0, _helpers.getComponentError)(component, validation === null || validation === void 0 ? void 0 : validation.errors)), container);
115
118
  }
@@ -202,6 +205,7 @@ FormComponent.propTypes = {
202
205
  id: _propTypes.default.string,
203
206
  label: _propTypes.default.string,
204
207
  suffix: _propTypes.default.string,
208
+ fieldset: _propTypes.default.bool,
205
209
  type: _propTypes.default.string,
206
210
  pageCollection: _propTypes.default.shape({
207
211
  name: _propTypes.default.string
@@ -366,5 +366,70 @@ describe('components', () => {
366
366
  _userEvent.default.upload(input, FILE);
367
367
  expect(ON_CHANGE_COUNT).toEqual(3);
368
368
  });
369
+ it('should render a text component appropriately when wrapped in a formGroups', async () => {
370
+ const ID = 'container';
371
+ const INNER_COMPONENT_ID = "text";
372
+ const VALUE = 'Text value';
373
+ const INNER_COMPONENT = {
374
+ id: INNER_COMPONENT_ID,
375
+ fieldId: INNER_COMPONENT_ID,
376
+ type: 'text',
377
+ label: 'Text component',
378
+ hint: 'Text hint',
379
+ value: VALUE
380
+ };
381
+ const COMPONENT = {
382
+ id: ID,
383
+ fieldId: ID,
384
+ type: 'container',
385
+ fieldset: true,
386
+ components: [INNER_COMPONENT]
387
+ };
388
+ const NESTED_VALUE = {
389
+ [INNER_COMPONENT_ID]: VALUE
390
+ };
391
+ const ON_CHANGE = () => {};
392
+ const {
393
+ container
394
+ } = (0, _setupTests.renderWithValidation)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_FormComponent.default, {
395
+ "data-testid": ID,
396
+ component: COMPONENT,
397
+ value: NESTED_VALUE,
398
+ onChange: ON_CHANGE
399
+ }));
400
+
401
+ // Form group
402
+ const formGroup = container.childNodes[0];
403
+ expect(formGroup.tagName).toEqual('DIV');
404
+ expect(formGroup.classList).toContain('govuk-form-group');
405
+ // FieldSet
406
+ const fieldSet = formGroup.childNodes[0];
407
+ expect(fieldSet.tagName).toEqual('FIELDSET');
408
+ expect(fieldSet.classList).toContain('govuk-fieldset');
409
+ // Form container
410
+ const formContainer = fieldSet.childNodes[0];
411
+ expect(formContainer.tagName).toEqual('DIV');
412
+ expect(formContainer.classList).toContain('hods-form-container');
413
+ // Form group for container
414
+ const formGroupForContainer = formContainer.childNodes[0];
415
+ expect(formGroupForContainer.tagName).toEqual('DIV');
416
+ expect(formGroupForContainer.classList).toContain('govuk-form-group');
417
+
418
+ // Nested component.
419
+ const label = formGroupForContainer.childNodes[0];
420
+ expect(label.tagName).toEqual('LABEL');
421
+ expect(label.classList).toContain('govuk-label');
422
+ expect(label.textContent).toEqual("".concat(INNER_COMPONENT.label, " (optional)"));
423
+ expect(label.getAttribute('for')).toEqual("".concat(ID, ".").concat(INNER_COMPONENT_ID));
424
+ const hint = formGroupForContainer.childNodes[1];
425
+ expect(hint.tagName).toEqual('DIV');
426
+ expect(hint.classList).toContain('govuk-hint');
427
+ expect(hint.textContent).toEqual(INNER_COMPONENT.hint);
428
+ const input = formGroupForContainer.childNodes[2];
429
+ expect(input.tagName).toEqual('INPUT');
430
+ expect(input.classList).toContain('govuk-input');
431
+ expect(input.id).toEqual("".concat(ID, ".").concat(INNER_COMPONENT_ID));
432
+ expect(input.value).toEqual(VALUE);
433
+ });
369
434
  });
370
435
  });
@@ -115,7 +115,8 @@ const FormPage = _ref => {
115
115
  label: _utils.default.interpolateString(action.label, formPage.formData)
116
116
  }) : action);
117
117
  formPage.formData = _utils.default.Operate.runPageOperations(formPage, _objectSpread(_objectSpread({}, formPage.formData), patch), onWrapperChange || onPageChange);
118
- const headingContent = page.title ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.LargeHeading, {
118
+ const headingContent = page.title ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.Heading, {
119
+ size: page.titleSize,
119
120
  children: _utils.default.FormPage.getTitle(page.title, page.formData)
120
121
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.Label, {
121
122
  id: page.id,
@@ -177,6 +178,7 @@ FormPage.propTypes = {
177
178
  page: _propTypes.default.shape({
178
179
  id: _propTypes.default.string.isRequired,
179
180
  title: _propTypes.default.string,
181
+ titleSize: _propTypes.default.string,
180
182
  components: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.shape({})])).isRequired,
181
183
  fieldset: _propTypes.default.bool,
182
184
  hideOptionalSuffix: _propTypes.default.bool,
@@ -11,10 +11,12 @@ var _FormPage = _interopRequireWildcard(require("./FormPage"));
11
11
  var _jsxRuntime = require("react/jsx-runtime");
12
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
- // Global imports
15
-
14
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
15
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
16
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
17
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
18
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } // Global imports
16
19
  // Local imports
17
-
18
20
  describe('components.FormPage', () => {
19
21
  describe('FormPage', () => {
20
22
  const TEXT = {
@@ -337,6 +339,63 @@ describe('components.FormPage', () => {
337
339
  }));
338
340
  expect(ON_ACTION_CALLS.length).toEqual(0);
339
341
  });
342
+ it('Should render the page title correctly.', async () => {
343
+ const {
344
+ container,
345
+ getByRole
346
+ } = (0, _setupTests.renderWithValidation)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_FormPage.default, {
347
+ page: PAGE_WITHOUT_CUSTOM_VALIDATION,
348
+ fromTarget: true,
349
+ onAction: ON_ACTION
350
+ }));
351
+ const heading = getByRole('heading', {
352
+ level: 1
353
+ });
354
+ const labels = container.querySelectorAll('label');
355
+ expect(labels).toHaveLength(1);
356
+ expect(labels[0]).toHaveTextContent('Text component');
357
+ expect(heading).toHaveTextContent('Page without Custom Validation');
358
+ });
359
+ it('Should render the page title correctly as a medium title', async () => {
360
+ const PAGE_WITH_TITLE_SIZE = _objectSpread(_objectSpread({}, PAGE_WITHOUT_CUSTOM_VALIDATION), {}, {
361
+ titleSize: 'm'
362
+ });
363
+ const {
364
+ container,
365
+ getByRole
366
+ } = (0, _setupTests.renderWithValidation)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_FormPage.default, {
367
+ page: PAGE_WITH_TITLE_SIZE,
368
+ fromTarget: true,
369
+ onAction: ON_ACTION
370
+ }));
371
+ const heading = getByRole('heading', {
372
+ level: 2
373
+ });
374
+ const labels = container.querySelectorAll('label');
375
+ expect(labels).toHaveLength(1);
376
+ expect(labels[0]).toHaveTextContent('Text component');
377
+ expect(heading).toHaveTextContent('Page without Custom Validation');
378
+ });
379
+ it('Should render the label correctly.', async () => {
380
+ const PAGE_WITHOUT_CUSTOM_VALIDATION_WITH_LABEL = _objectSpread(_objectSpread({}, PAGE_WITHOUT_CUSTOM_VALIDATION), {}, {
381
+ label: 'Some label value'
382
+ });
383
+ delete PAGE_WITHOUT_CUSTOM_VALIDATION_WITH_LABEL.title;
384
+ const {
385
+ container,
386
+ queryByRole
387
+ } = (0, _setupTests.renderWithValidation)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_FormPage.default, {
388
+ page: PAGE_WITHOUT_CUSTOM_VALIDATION_WITH_LABEL,
389
+ fromTarget: true,
390
+ onAction: ON_ACTION
391
+ }));
392
+ const labels = container.querySelectorAll('label');
393
+ const heading = queryByRole('heading');
394
+ expect(labels).toHaveLength(2);
395
+ expect(labels[0]).toHaveTextContent('Some label value');
396
+ expect(labels[1]).toHaveTextContent('Text component');
397
+ expect(heading).not.toBeInTheDocument();
398
+ });
340
399
  it('removed field from the form data when the value is set to null', () => {
341
400
  const AUTOCOMPLETE = {
342
401
  id: 'autocomplete',
@@ -4,9 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = exports.DEFAULT_CLASS = void 0;
7
- var _copReactComponents = require("@ukhomeoffice/cop-react-components");
8
7
  var _react = _interopRequireWildcard(require("react"));
9
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
+ var _copReactComponents = require("@ukhomeoffice/cop-react-components");
10
10
  var _context = require("../../context");
11
11
  var _hooks = require("../../hooks");
12
12
  var _models = require("../../models");
@@ -37,6 +37,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
37
37
  const FormRenderer = _ref => {
38
38
  let {
39
39
  title,
40
+ titleSize,
40
41
  type,
41
42
  cleanseHiddenData,
42
43
  components,
@@ -61,6 +62,7 @@ const FormRenderer = _ref => {
61
62
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_context.ValidationContextProvider, {
62
63
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(InternalFormRenderer, {
63
64
  title: title,
65
+ titleSize: titleSize,
64
66
  type: type,
65
67
  cleanseHiddenData: cleanseHiddenData,
66
68
  components: components,
@@ -87,6 +89,7 @@ const InternalFormRenderer = _ref2 => {
87
89
  var _formState$page4, _formState$page$actio, _formState$cya$hideCh, _formState$cya$hideGr;
88
90
  let {
89
91
  title,
92
+ titleSize,
90
93
  type,
91
94
  cleanseHiddenData,
92
95
  components,
@@ -305,7 +308,8 @@ const InternalFormRenderer = _ref2 => {
305
308
  taskDetails = _objectWithoutProperties(hubDetails, _excluded);
306
309
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
307
310
  className: classes(),
308
- children: [title && !hideTitle && pageId === _models.FormPages.HUB && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.LargeHeading, {
311
+ children: [title && !hideTitle && pageId === _models.FormPages.HUB && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.Heading, {
312
+ size: titleSize,
309
313
  children: title
310
314
  }), formState.cya && /*#__PURE__*/(0, _jsxRuntime.jsx)(_CheckYourAnswers.default, _objectSpread(_objectSpread(_objectSpread(_objectSpread({
311
315
  pages: _helpers.default.getRelevantPages(formState, pages, currentTask.fullPages)
@@ -382,6 +386,7 @@ const propTypes = {
382
386
  pages: _propTypes.default.arrayOf(_propTypes.default.shape({})).isRequired,
383
387
  summaryListClassModifiers: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
384
388
  title: _propTypes.default.string,
389
+ titleSize: _propTypes.default.string,
385
390
  cleanseHiddenData: _propTypes.default.bool,
386
391
  /** See <a href="/?path=/docs/f-json--page#formtypes">FormTypes</a>. */
387
392
  type: _propTypes.default.oneOf([_models.FormTypes.CYA, _models.FormTypes.FORM, _models.FormTypes.HUB, _models.FormTypes.TASK, _models.FormTypes.WIZARD, _models.FormTypes.TASK_CYA, _models.FormTypes.FORM_WITH_TASK]).isRequired,
@@ -408,6 +413,7 @@ const defaultProps = {
408
413
  noChangeAction: false,
409
414
  summaryListClassModifiers: [],
410
415
  title: '',
416
+ titleSize: 'l',
411
417
  cleanseHiddenData: false,
412
418
  viewOnly: true,
413
419
  hideBlankRows: false
@@ -14,7 +14,7 @@ var _SummaryListHeadingRowWithAction = _interopRequireDefault(require("./Summary
14
14
  var _SummaryListTitleRow = _interopRequireDefault(require("./SummaryListTitleRow"));
15
15
  require("./SummaryList.scss");
16
16
  var _jsxRuntime = require("react/jsx-runtime");
17
- const _excluded = ["rows", "noChangeAction", "noGroupAction", "isGroup", "classBlock", "classModifiers", "className"]; // Global imports
17
+ const _excluded = ["rows", "noChangeAction", "noGroupAction", "isGroup", "classBlock", "classModifiers", "className", "showGroupAction"]; // Global imports
18
18
  // Local imports
19
19
  // Styles
20
20
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -34,7 +34,8 @@ const SummaryList = _ref => {
34
34
  isGroup,
35
35
  classBlock,
36
36
  classModifiers,
37
- className
37
+ className,
38
+ showGroupAction = true
38
39
  } = _ref,
39
40
  attrs = _objectWithoutProperties(_ref, _excluded);
40
41
  const classes = _copReactComponents.Utils.classBuilder(classBlock, classModifiers, className);
@@ -48,6 +49,7 @@ const SummaryList = _ref => {
48
49
  className: "group-of-rows",
49
50
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, cleanedHtmlAttrs), {}, {
50
51
  className: classes(),
52
+ role: "list",
51
53
  children: [rows.map(row => {
52
54
  const key = "".concat(row.pageId, "_").concat(row.full_path || row.fieldId);
53
55
  if (row.type === 'title') {
@@ -82,7 +84,7 @@ const SummaryList = _ref => {
82
84
  classes: classes,
83
85
  showAction: !noChangeAction
84
86
  }, key);
85
- }).filter(r => !!r), isGroup && !noGroupAction && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
87
+ }).filter(r => !!r), showGroupAction && isGroup && !noGroupAction && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
86
88
  className: "change-group-button",
87
89
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_GroupAction.default, {
88
90
  group: groupActionRow
@@ -98,6 +100,7 @@ SummaryList.propTypes = {
98
100
  isGroup: _propTypes.default.bool,
99
101
  noChangeAction: _propTypes.default.bool,
100
102
  noGroupAction: _propTypes.default.bool,
103
+ showGroupAction: _propTypes.default.bool,
101
104
  rows: _propTypes.default.arrayOf(_propTypes.default.shape({
102
105
  pageId: _propTypes.default.string.isRequired,
103
106
  fieldId: _propTypes.default.string.isRequired,
@@ -118,6 +121,7 @@ SummaryList.defaultProps = {
118
121
  className: '',
119
122
  isGroup: false,
120
123
  noChangeAction: false,
121
- noGroupAction: false
124
+ noGroupAction: false,
125
+ showGroupAction: true
122
126
  };
123
127
  var _default = exports.default = SummaryList;
@@ -443,6 +443,61 @@ describe('components', () => {
443
443
  expect(valueDiv.tagName).toEqual('DIV');
444
444
  expect(valueDiv.textContent).toEqual(VALUES[index]);
445
445
  });
446
+ // Expect the group action to be rendered at the bottom of the summary.
447
+ const groupAction = summaryList.childNodes[ROWS.length].childNodes[0];
448
+ expect(groupAction.tagName).toEqual('A');
449
+ expect(groupAction.textContent).toEqual('action');
450
+ });
451
+ it('should render groups of rows correctly and no render the group action', () => {
452
+ const ID = 'test-id';
453
+ const VALUES = ['Alpha component value', 'Bravo component value', 'Charlie component value'];
454
+ const ISGROUP = true;
455
+ const ROWS = [{
456
+ key: 'a',
457
+ pageId: 'p1',
458
+ fieldId: 'a',
459
+ value: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
460
+ children: VALUES[0]
461
+ }),
462
+ action: {
463
+ label: 'action'
464
+ }
465
+ }, {
466
+ key: 'b',
467
+ pageId: 'p1',
468
+ fieldId: 'b',
469
+ value: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
470
+ children: VALUES[1]
471
+ })
472
+ }, {
473
+ key: 'c',
474
+ pageId: 'p1',
475
+ fieldId: 'c',
476
+ value: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
477
+ children: VALUES[2]
478
+ })
479
+ }];
480
+ const {
481
+ container
482
+ } = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_SummaryList.default, {
483
+ "data-testid": ID,
484
+ rows: ROWS,
485
+ isGroup: ISGROUP,
486
+ showGroupAction: false
487
+ }));
488
+ const summaryList = checkSummaryList(container, ID);
489
+ expect(summaryList.childNodes.length).toEqual(ROWS.length);
490
+ ROWS.forEach((row, index) => {
491
+ const [key, value] = checkRow(summaryList, index);
492
+ expect(key.textContent).toEqual("".concat(row.key, " (optional)"));
493
+ expect(value.childNodes.length).toEqual(1);
494
+ const valueDiv = value.childNodes[0];
495
+ expect(valueDiv.tagName).toEqual('DIV');
496
+ expect(valueDiv.textContent).toEqual(VALUES[index]);
497
+ });
498
+ // Expect the group action to not be rendered.
499
+ const groupAction = summaryList.childNodes[ROWS.length];
500
+ expect(groupAction).toBeUndefined();
446
501
  });
447
502
  });
448
503
  });
@@ -19,6 +19,7 @@ const SummaryListHeadingRow = _ref => {
19
19
  } = _ref;
20
20
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
21
21
  className: "".concat(classes('heading')),
22
+ role: "listitem",
22
23
  children: [size === 's' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.SmallHeading, {
23
24
  children: title
24
25
  }), size === 'm' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.MediumHeading, {
@@ -25,6 +25,7 @@ const SummaryListHeadingRowWithAction = _ref => {
25
25
  } = _ref;
26
26
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
27
27
  className: classes('headingWithAction'),
28
+ role: "listitem",
28
29
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("td", {
29
30
  className: "heading-text",
30
31
  colSpan: "2",
@@ -21,6 +21,7 @@ const SummaryListRow = _ref => {
21
21
  } = _ref;
22
22
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("dl", {
23
23
  className: classes('row'),
24
+ role: "listitem",
24
25
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("dt", {
25
26
  className: classes('key'),
26
27
  children: [row.key, !row.required && " (optional)"]
@@ -18,6 +18,7 @@ const SummaryListTitleRow = _ref => {
18
18
  } = _ref;
19
19
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
20
20
  className: "".concat(classes('row'), " ").concat(classes('title')),
21
+ role: "listitem",
21
22
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_copReactComponents.SmallHeading, {
22
23
  children: title
23
24
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukhomeoffice/cop-react-form-renderer",
3
- "version": "7.2.0",
3
+ "version": "7.3.1",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "build-storybook": "storybook build",
@@ -18,7 +18,7 @@
18
18
  "yalc-publish": "yarn compile-with-maps && cp -r src dist/src && yalc publish --push"
19
19
  },
20
20
  "dependencies": {
21
- "@ukhomeoffice/cop-react-components": "5.1.0",
21
+ "@ukhomeoffice/cop-react-components": "5.1.2",
22
22
  "axios": "0.30.0",
23
23
  "dayjs": "^1.11.0",
24
24
  "govuk-frontend": "5.10.2",