@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.
- package/dist/components/CheckYourAnswers/CheckYourAnswers.js +5 -1
- package/dist/components/CollectionSummary/RenderListView.js +1 -0
- package/dist/components/CollectionSummary/SummaryCardDetails.js +3 -0
- package/dist/components/FormComponent/Container.js +7 -4
- package/dist/components/FormComponent/Container.test.js +45 -0
- package/dist/components/FormComponent/FormComponent.js +4 -0
- package/dist/components/FormComponent/FormComponent.test.js +65 -0
- package/dist/components/FormPage/FormPage.js +3 -1
- package/dist/components/FormPage/FormPage.test.js +62 -3
- package/dist/components/FormRenderer/FormRenderer.js +8 -2
- package/dist/components/SummaryList/SummaryList.js +8 -4
- package/dist/components/SummaryList/SummaryList.test.js +55 -0
- package/dist/components/SummaryList/SummaryListHeadingRow.js +1 -0
- package/dist/components/SummaryList/SummaryListHeadingRowWithAction.js +1 -0
- package/dist/components/SummaryList/SummaryListRow.js +1 -0
- package/dist/components/SummaryList/SummaryListTitleRow.js +1 -0
- package/package.json +2 -2
|
@@ -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.
|
|
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.
|
|
74
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, cleanedAttrs), {}, {
|
|
75
75
|
className: classes(),
|
|
76
76
|
id: container.id,
|
|
77
|
-
children: container.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|