diff --git a/README.md b/README.md
index 64c9aa2c30..f9a8eb92af 100644
--- a/README.md
+++ b/README.md
@@ -158,3 +158,4 @@ yarn build
- "render whitespace" set to "all"
- "insert spaces when pressing tab" checked
+- "trim trailing whitespace" checked
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_0_desktop.png b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_0_desktop.png
new file mode 100644
index 0000000000..e797516193
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_0_desktop.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:366c9aff9124200ace7d097a2227d594b42984ac5ebd47692a6126dcd4e231b2
+size 18957
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_1_tablet.png b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_1_tablet.png
new file mode 100644
index 0000000000..a46d9543a1
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_1_tablet.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c95488d7659a0768dd81b0c0125abca78833f378e1418a76d063db2bb0d83208
+size 13842
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_2_mobile.png b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_2_mobile.png
new file mode 100644
index 0000000000..b1b4c7e3be
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-double-field_0_document_2_mobile.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4e2f1d3d2f3d77101db234493308ed89060a298ce510e3e1cea26877c4e47ac9
+size 10587
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_0_desktop.png b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_0_desktop.png
new file mode 100644
index 0000000000..9db40cc6b4
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_0_desktop.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:55948fafb4f0efcd5d807ecd6b4c926fadd1bd21b7bb3568157ca067c6dcf0d4
+size 15409
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_1_tablet.png b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_1_tablet.png
new file mode 100644
index 0000000000..ce0b2d4e69
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_1_tablet.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cb3d3f12ab40e4866c156f63f7bd02b4f61a01914472460bfe172562934075b2
+size 10290
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_2_mobile.png b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_2_mobile.png
new file mode 100644
index 0000000000..c04dc2134d
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_date-input_example-date-input-single-field_0_document_2_mobile.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ee6549c14f27303bb82cc63a8896548371b950c3ddc0b9b7cfa3e45835d43b72
+size 7231
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_0_desktop.png b/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_0_desktop.png
new file mode 100644
index 0000000000..168c736c4c
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_0_desktop.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:71378caad810dbb6135ad8418f26e9c92cba6f9c5a4e49d5ab66b3c746d148a7
+size 24525
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_1_tablet.png b/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_1_tablet.png
new file mode 100644
index 0000000000..c37edbd254
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_1_tablet.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:05c6bd046dd5fc0d58b621a65b79d0878e870f243c8f99902908cc50f393d5f5
+size 20703
diff --git a/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_2_mobile.png b/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_2_mobile.png
new file mode 100644
index 0000000000..8554d76a96
--- /dev/null
+++ b/backstop_data/bitmaps_reference/ds-vr-test__components_duration_example-duration-single-field_0_document_2_mobile.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b9b00c14d40f57790571900e616d8473c7e3f9c5e93e1e83066f9aee8576f960
+size 20778
diff --git a/src/components/date-field-input/_macro.njk b/src/components/date-field-input/_macro.njk
deleted file mode 100644
index a53b43461d..0000000000
--- a/src/components/date-field-input/_macro.njk
+++ /dev/null
@@ -1,86 +0,0 @@
-{% from "components/mutually-exclusive/_macro.njk" import onsMutuallyExclusive %}
-{% from "components/fieldset/_macro.njk" import onsFieldset %}
-{% from "components/input/_macro.njk" import onsInput %}
-{% from "components/error/_macro.njk" import onsError %}
-
-{% macro onsDateFieldInput(params) %}
- {% set fields %}
- {% for field in params.fields %}
- {{
- onsInput({
- "id": field.id,
- "classes": field.classes,
- "width": field.width,
- "type": "number",
- "name": field.name,
- "value": field.value,
- "min": field.min,
- "max": field.max,
- "maxLength": field.maxLength,
- "suffix": field.suffix,
- "label": field.label,
- "attributes": field.attributes,
- "error": field.error,
- "fieldId": field.fieldId
- })
- }}
- {% endfor %}
- {% endset %}
-
- {% if numberOfFields > 1 %}
- {% set fields %}
-
- {{ fields | safe }}
-
- {% endset %}
- {% endif %}
-
- {% if params.mutuallyExclusive %}
- {% set mutuallyExclusive = params.mutuallyExclusive | setAttributes({
- "id": params.id,
- "legend": params.legendOrLabel,
- "legendClasses": params.legendClasses,
- "description": params.description,
- "error": params.error,
- "classes": params.classes,
- "legendIsQuestionTitle": params.legendIsQuestionTitle,
- "dontWrap": params.dontWrap,
- "exclusiveOptions": params.mutuallyExclusive.exclusiveOptions,
- "or": params.mutuallyExclusive.or,
- "deselectMessage": params.mutuallyExclusive.deselectMessage,
- "deselectGroupAdjective": params.mutuallyExclusive.deselectGroupAdjective,
- "deselectExclusiveOptionAdjective": params.mutuallyExclusive.deselectExclusiveOptionAdjective
- }) %}
-
- {% call onsMutuallyExclusive(mutuallyExclusive) %}
-
- {{ fields | safe }}
-
- {% endcall %}
- {% elif params.numberOfFields > 1 %}
- {% call onsFieldset({
- "id": params.id,
- "legend": params.legendOrLabel,
- "classes": params.classes,
- "description": params.description,
- "legendClasses": params.legendClasses,
- "error": params.error,
- "legendIsQuestionTitle": params.legendIsQuestionTitle,
- "dontWrap": params.dontWrap
- }) %}
-
- {{ fields | safe }}
-
- {% endcall %}
- {% elif params.numberOfFields == 1 %}
- {% if params.error %}
- {% call onsError(params.error) %}
- {{ fields | safe }}
- {% endcall %}
- {% else %}
- {{ fields | safe }}
- {% endif %}
- {% else %}
- {{ fields | safe }}
- {% endif %}
-{% endmacro %}
diff --git a/src/components/date-input/_macro.njk b/src/components/date-input/_macro.njk
index 3f354844e4..a0f700d33f 100644
--- a/src/components/date-input/_macro.njk
+++ b/src/components/date-input/_macro.njk
@@ -1,8 +1,9 @@
-{% from "components/date-field-input/_macro.njk" import onsDateFieldInput %}
+{% from "components/multiple-input-fields/_macro.njk" import onsMultipleInputFields %}
+{% from "components/input/_macro.njk" import onsInput %}
{% macro onsDateInput(params) %}
{% set exclusiveClass = " ons-js-exclusive-group-item" if params.mutuallyExclusive else "" %}
- {%- set numberOfFields = 0 -%}
+ {%- set numberOfFields = 0 -%}
{%- if params.day -%}
{%- set numberOfFields = numberOfFields + 1 -%}
@@ -16,82 +17,83 @@
{%- set numberOfFields = numberOfFields + 1 -%}
{%- endif -%}
- {% set fields = [] %}
- {% if params.day %}
- {% set dayField = {
- "id": params.id + "-day",
- "label": {
- "text": params.day.label.text if numberOfFields > 1 else params.legendOrLabel,
- "description": params.day.label.description if numberOfFields > 1 else params.description,
- "id": params.id + "-day-label"
- },
- "name": params.day.name,
- "width": "2",
- "min": 1,
- "max": 31,
- "maxLength": 2,
- "attributes": params.day.attributes,
- "value": params.day.value,
- "classes": (" ons-input--error" if (params.error and params.day.error) or (params.error and not params.day.error and not params.month.error and not params.year.error) else "") + exclusiveClass | default("")
- } %}
- {% set fields = (fields.push(dayField), fields) %}
- {% endif %}
- {% if params.month %}
- {% set monthField = {
- "id": params.id + "-month",
- "label": {
- "text": params.month.label.text if numberOfFields > 1 else params.legendOrLabel,
- "description": params.month.label.description if numberOfFields > 1 else params.description,
- "id": params.id + "-month-label"
- },
- "name": params.month.name,
- "width": "2",
- "min": 1,
- "max": 12,
- "maxLength": 2,
- "attributes": params.month.attributes,
- "value": params.month.value,
- "classes": (" ons-input--error" if (params.error and params.month.error) or (params.error and not params.day.error and not params.month.error and not params.year.error) else "") + exclusiveClass | default("")
- } %}
- {% set fields = (fields.push(monthField), fields) %}
- {% endif %}
- {% if params.year %}
- {% set yearField = {
- "id": params.id + "-year",
- "label": {
- "text": params.year.label.text if numberOfFields > 1 else params.legendOrLabel,
- "description": params.year.label.description if numberOfFields > 1 else params.description,
- "id": params.id + "-year-label"
- },
- "name": params.year.name,
- "width": "4",
- "min": 1000,
- "max": 3000,
- "maxLength": 4,
- "attributes": params.year.attributes,
- "value": params.year.value,
- "classes": (" ons-input--error" if (params.error and params.year.error) or (params.error and not params.day.error and not params.month.error and not params.year.error) else "") + exclusiveClass | default("")
- } %}
- {% set fields = (fields.push(yearField), fields) %}
- {% endif %}
+ {% set fields %}
+ {% if params.day %}
+ {{ onsInput({
+ "id": params.id + "-day",
+ "type": "number",
+ "name": params.day.name,
+ "classes": (" ons-input--error" if (params.error and params.day.error) or (params.error and not params.day.error and not params.month.error and not params.year.error) else "") + exclusiveClass | default(""),
+ "width": "2",
+ "min": 1,
+ "max": 31,
+ "maxLength": 2,
+ "attributes": params.day.attributes,
+ "label": {
+ "text": params.day.label.text if numberOfFields > 1 else params.legendOrLabel,
+ "description": params.day.label.description if numberOfFields > 1 else params.description,
+ "id": params.id + "-day-label"
+ },
+ "value": params.day.value,
+ "error": params.error if numberOfFields < 2
+ }) }}
+ {% endif %}
- {{ onsDateFieldInput({
+ {% if params.month %}
+ {{ onsInput({
+ "id": params.id + "-month",
+ "type": "number",
+ "name": params.month.name,
+ "classes": (" ons-input--error" if (params.error and params.month.error) or (params.error and not params.day.error and not params.month.error and not params.year.error) else "") + exclusiveClass | default(""),
+ "width": "2",
+ "min": 1,
+ "max": 12,
+ "maxLength": 2,
+ "attributes": params.month.attributes,
+ "label": {
+ "text": params.month.label.text if numberOfFields > 1 else params.legendOrLabel,
+ "description": params.month.label.description if numberOfFields > 1 else params.description,
+ "id": params.id + "-month-label"
+ },
+ "value": params.month.value,
+ "error": params.error if numberOfFields < 2
+ }) }}
+ {% endif %}
+
+ {% if params.year %}
+ {{ onsInput({
+ "id": params.id + "-year",
+ "type": "number",
+ "name": params.year.name,
+ "classes": (" ons-input--error" if (params.error and params.year.error) or (params.error and not params.day.error and not params.month.error and not params.year.error) else "") + exclusiveClass | default(""),
+ "width": "4",
+ "min": 1000,
+ "max": 3000,
+ "maxLength": 4,
+ "attributes": params.year.attributes,
+ "label": {
+ "text": params.year.label.text if numberOfFields > 1 else params.legendOrLabel,
+ "description": params.year.label.description if numberOfFields > 1 else params.description,
+ "id": params.id + "-year-label"
+ },
+ "value": params.year.value,
+ "error": params.error if numberOfFields < 2
+ }) }}
+ {% endif %}
+ {% endset %}
+
+ {{ onsMultipleInputFields({
"id": params.id,
"legendOrLabel": params.legendOrLabel,
"description": params.description,
"mutuallyExclusive": params.mutuallyExclusive,
- "fields": fields,
"numberOfFields": numberOfFields,
+ "fields": fields,
"error": params.error,
"legend": params.legendOrLabel,
"dontWrap": params.dontWrap,
- "legendClasses": params.legendClasses,
- "legendIsQuestionTitle": params.legendIsQuestionTitle,
"classes": params.classes,
- "exclusiveOptions": params.mutuallyExclusive.exclusiveOptions,
- "or": params.mutuallyExclusive.or,
- "deselectMessage": params.mutuallyExclusive.deselectMessage,
- "deselectGroupAdjective": params.mutuallyExclusive.deselectGroupAdjective,
- "deselectExclusiveOptionAdjective": params.mutuallyExclusive.deselectExclusiveOptionAdjective
+ "legendClasses": params.legendClasses,
+ "legendIsQuestionTitle": params.legendIsQuestionTitle
}) }}
{% endmacro %}
diff --git a/src/components/date-input/_macro.spec.js b/src/components/date-input/_macro.spec.js
index 7c5e99c1cc..e4a8b7ac42 100644
--- a/src/components/date-input/_macro.spec.js
+++ b/src/components/date-input/_macro.spec.js
@@ -107,7 +107,7 @@ const EXAMPLE_YEAR_FIELD_WITH_ERROR = {
},
};
-const EXAMPLE_YEAR_FIELD_WITH_NO_ERROR = {
+const EXAMPLE_YEAR_FIELD_WITH_ERROR_FALSE = {
year: {
label: {
text: 'Year',
@@ -148,9 +148,9 @@ const EXAMPLE_DATE_MULTIPLE_FIELDS_WITH_ERROR = {
...EXAMPLE_YEAR_FIELD_WITH_ERROR,
};
-const EXAMPLE_DATE_MULTIPLE_FIELDS_WITH_NO_ERROR = {
+const EXAMPLE_DATE_SINGLE_FIELD_WITH_ERROR_FALSE = {
...EXAMPLE_DATE_INPUT_BASE,
- ...EXAMPLE_YEAR_FIELD_WITH_NO_ERROR,
+ ...EXAMPLE_YEAR_FIELD_WITH_ERROR_FALSE,
};
describe('macro: date input', () => {
@@ -177,6 +177,7 @@ describe('macro: date input', () => {
max: 31,
maxLength: 2,
classes: '',
+ error: '',
label: {
text: 'Day',
description: 'The day',
@@ -204,6 +205,7 @@ describe('macro: date input', () => {
max: 12,
maxLength: 2,
classes: '',
+ error: '',
label: {
text: 'Month',
description: 'The month',
@@ -231,6 +233,7 @@ describe('macro: date input', () => {
max: 3000,
maxLength: 4,
classes: '',
+ error: '',
label: {
text: 'Year',
description: 'The year',
@@ -249,6 +252,12 @@ describe('macro: date input', () => {
expect($(div).hasClass('ons-field-group')).toBe(true);
});
+ it('has the correct number of inputs', () => {
+ const $ = cheerio.load(renderComponent('date-input', EXAMPLE_DATE_MULTIPLE_FIELDS));
+ const $inputs = $('.ons-input');
+ expect($inputs.length).toBe(3);
+ });
+
it('has the expected `fieldset` output', () => {
const faker = templateFaker();
const fieldsetSpy = faker.spy('fieldset');
@@ -356,6 +365,12 @@ describe('macro: date input', () => {
});
});
+ it('has the correct number of inputs', () => {
+ const $ = cheerio.load(renderComponent('date-input', EXAMPLE_DATE_SINGLE_FIELD));
+ const $inputs = $('.ons-input');
+ expect($inputs.length).toBe(1);
+ });
+
it('has the expected `error` output', () => {
const faker = templateFaker();
const errorSpy = faker.spy('error');
@@ -371,7 +386,7 @@ describe('macro: date input', () => {
});
});
- describe('mode: multiple fields with single field error', () => {
+ describe('mode: multiple fields with errors', () => {
it('passes jest-axe checks', async () => {
const $ = cheerio.load(renderComponent('date-input', EXAMPLE_DATE_MULTIPLE_FIELDS_WITH_SINGLE_ERROR));
@@ -394,7 +409,7 @@ describe('macro: date input', () => {
});
it('does not provide error class when error parameter set to false', async () => {
- const $ = cheerio.load(renderComponent('date-input', EXAMPLE_DATE_MULTIPLE_FIELDS_WITH_NO_ERROR));
+ const $ = cheerio.load(renderComponent('date-input', EXAMPLE_DATE_SINGLE_FIELD_WITH_ERROR_FALSE));
const $errorContent = $('.ons-input--error');
expect($errorContent.length).toBe(0);
diff --git a/src/components/date-input/example-date-input-double-field.njk b/src/components/date-input/example-date-input-double-field.njk
new file mode 100644
index 0000000000..28019c475c
--- /dev/null
+++ b/src/components/date-input/example-date-input-double-field.njk
@@ -0,0 +1,27 @@
+{% from "components/date-input/_macro.njk" import onsDateInput %}
+
+{{
+ onsDateInput({
+ "id": "date-input-example-double",
+ "legendOrLabel": "Month and year of last MOT",
+ "description": "For example, 3 2023",
+ "month": {
+ "label": {
+ "text": "Month"
+ },
+ "name": "month",
+ "attributes": {
+ "autocomplete": "mot-month"
+ }
+ },
+ "year": {
+ "label": {
+ "text": "Year"
+ },
+ "name": "year",
+ "attributes": {
+ "autocomplete": "mot-year"
+ }
+ }
+ })
+}}
diff --git a/src/components/date-input/example-date-input-single-field.njk b/src/components/date-input/example-date-input-single-field.njk
new file mode 100644
index 0000000000..39bc0d9eb8
--- /dev/null
+++ b/src/components/date-input/example-date-input-single-field.njk
@@ -0,0 +1,18 @@
+{% from "components/date-input/_macro.njk" import onsDateInput %}
+
+{{
+ onsDateInput({
+ "id": "date-input-example-single",
+ "legendOrLabel": "Year of birth",
+ "description": "For example, 1980",
+ "year": {
+ "label": {
+ "text": "Year"
+ },
+ "name": "year",
+ "attributes": {
+ "autocomplete": "bday-year"
+ }
+ }
+ })
+}}
diff --git a/src/components/duration/_macro.njk b/src/components/duration/_macro.njk
index 871e5d11cc..7d04d6ae2d 100644
--- a/src/components/duration/_macro.njk
+++ b/src/components/duration/_macro.njk
@@ -1,7 +1,10 @@
-{% from "components/date-field-input/_macro.njk" import onsDateFieldInput %}
+{% from "components/multiple-input-fields/_macro.njk" import onsMultipleInputFields %}
+{% from "components/input/_macro.njk" import onsInput %}
{% macro onsDuration(params) %}
+ {% set exclusiveClass = " ons-js-exclusive-group-item" if params.mutuallyExclusive else "" %}
{% set numberOfFields = 0 %}
+
{% if params.field1 %}
{% set numberOfFields = numberOfFields + 1 %}
{% endif %}
@@ -10,54 +13,55 @@
{% set numberOfFields = numberOfFields + 1 %}
{% endif %}
- {% set fields = [] %}
- {% if params.field1 %}
- {% set field1 = {
- "id": params.field1.id,
- "name": params.field1.name,
- "attributes": params.field1.attributes,
- "label": {
- "text": params.legendOrLabel if numberOfFields < 2,
- "description": params.description if numberOfFields < 2
- },
- "suffix": {
- "text": params.field1.suffix.text,
- "title": params.field1.suffix.title,
- "id": params.field1.suffix.id
- },
- "width": "2",
- "fieldId": params.id if numberOfFields < 2,
- "value": params.field1.value,
- "error": params.error if numberOfFields < 2,
- "classes": (" ons-input--error" if (params.error and params.field1.error) or (params.error and not params.field1.error and not params.field2.error) else "") + (" ons-js-exclusive-group-item" if params.mutuallyExclusive else "")
- } %}
- {% set fields = (fields.push(field1), fields) %}
- {% endif %}
+ {% set fields %}
+ {% if params.field1 %}
+ {{ onsInput({
+ "id": params.field1.id,
+ "type": "number",
+ "name": params.field1.name,
+ "classes": (" ons-input--error" if (params.error and params.field1.error) or (numberOfFields > 1 and params.error and not params.field1.error and not params.field2.error) else "") + exclusiveClass | default(""),
+ "width": "2",
+ "attributes": params.field1.attributes,
+ "value": params.field1.value,
+ "suffix": {
+ "text": params.field1.suffix.text,
+ "title": params.field1.suffix.title,
+ "id": params.field1.suffix.id
+ },
+ "label": {
+ "text": params.legendOrLabel if numberOfFields < 2,
+ "description": params.description if numberOfFields < 2
+ },
+ "fieldId": params.id if numberOfFields < 2,
+ "error": params.error if numberOfFields < 2
+ }) }}
+ {% endif %}
- {% if params.field2 %}
- {% set field2 = {
- "id": params.field2.id,
- "name": params.field2.name,
- "attributes": params.field2.attributes,
- "width": "2",
- "label": {
- "text": params.legendOrLabel if numberOfFields < 2,
- "description": params.description if numberOfFields < 2
- },
- "suffix": {
- "text": params.field2.suffix.text,
- "title": params.field2.suffix.title,
- "id": params.field2.suffix.id
- },
- "value": params.field2.value,
- "error": params.error if numberOfFields < 2,
- "fieldId": params.id if numberOfFields < 2,
- "classes": (" ons-input--error" if (params.error and params.field2.error) or (params.error and not params.field1.error and not params.field2.error) else "") + (" ons-js-exclusive-group-item" if params.mutuallyExclusive else "")
- } %}
- {% set fields = (fields.push(field2), fields) %}
- {% endif %}
-
- {{ onsDateFieldInput({
+ {% if params.field2 %}
+ {{ onsInput({
+ "id": params.field2.id,
+ "type": "number",
+ "name": params.field2.name,
+ "classes": (" ons-input--error" if (params.error and params.field2.error) or (numberOfFields > 1 and params.error and not params.field1.error and not params.field2.error) else "") + exclusiveClass | default(""),
+ "width": "2",
+ "attributes": params.field2.attributes,
+ "value": params.field2.value,
+ "suffix": {
+ "text": params.field2.suffix.text,
+ "title": params.field2.suffix.title,
+ "id": params.field2.suffix.id
+ },
+ "label": {
+ "text": params.legendOrLabel if numberOfFields < 2,
+ "description": params.description if numberOfFields < 2
+ },
+ "fieldId": params.id if numberOfFields < 2,
+ "error": params.error if numberOfFields < 2
+ }) }}
+ {% endif %}
+ {% endset %}
+
+ {{ onsMultipleInputFields({
"id": params.id,
"legendOrLabel": params.legendOrLabel,
"description": params.description,
diff --git a/src/components/duration/_macro.spec.js b/src/components/duration/_macro.spec.js
index 25eb9cff42..d4bf88c1cb 100644
--- a/src/components/duration/_macro.spec.js
+++ b/src/components/duration/_macro.spec.js
@@ -11,6 +11,15 @@ const EXAMPLE_DURATION_INPUT_BASE = {
description: 'Enter “0” into the years field if you have lived at this address for less than a year',
};
+const EXAMPLE_DURATION_INPUT_BASE_WITH_ERROR = {
+ id: 'duration',
+ legendOrLabel: 'How long have you lived at this address?',
+ description: 'Enter “0” into the years field if you have lived at this address for less than a year',
+ error: {
+ text: 'Enter how long you have lived at this address',
+ },
+};
+
const EXAMPLE_FIELD_1 = {
field1: {
id: 'address-duration-years',
@@ -35,6 +44,45 @@ const EXAMPLE_FIELD_2 = {
},
};
+const EXAMPLE_FIELD_1_WITH_ERROR = {
+ field1: {
+ id: 'address-duration-years',
+ name: 'address-duration-years',
+ value: '0',
+ error: true,
+ suffix: {
+ text: 'Years',
+ id: 'address-duration-years-suffix',
+ },
+ },
+};
+
+const EXAMPLE_FIELD_2_WITH_ERROR = {
+ field2: {
+ id: 'address-duration-months',
+ name: 'address-duration-months',
+ value: '0',
+ error: true,
+ suffix: {
+ text: 'Months',
+ id: 'address-duration-months-suffix',
+ },
+ },
+};
+
+const EXAMPLE_FIELD_1_WITH_ERROR_FALSE = {
+ field1: {
+ id: 'address-duration-years',
+ name: 'address-duration-years',
+ value: '0',
+ error: false,
+ suffix: {
+ text: 'Years',
+ id: 'address-duration-years-suffix',
+ },
+ },
+};
+
const EXAMPLE_DURATION_SINGLE_FIELD = {
...EXAMPLE_DURATION_INPUT_BASE,
...EXAMPLE_FIELD_1,
@@ -46,6 +94,23 @@ const EXAMPLE_DURATION_MULTIPLE_FIELDS = {
...EXAMPLE_FIELD_2,
};
+const EXAMPLE_DURATION_MULTIPLE_FIELDS_WITH_SINGLE_ERROR = {
+ ...EXAMPLE_DURATION_INPUT_BASE_WITH_ERROR,
+ ...EXAMPLE_FIELD_1,
+ ...EXAMPLE_FIELD_2_WITH_ERROR,
+};
+
+const EXAMPLE_DURATION_MULTIPLE_FIELDS_WITH_ERROR = {
+ ...EXAMPLE_DURATION_INPUT_BASE_WITH_ERROR,
+ ...EXAMPLE_FIELD_1_WITH_ERROR,
+ ...EXAMPLE_FIELD_2_WITH_ERROR,
+};
+
+const EXAMPLE_DURATION_MULTIPLE_FIELDS_WITH_ERROR_FALSE = {
+ ...EXAMPLE_DURATION_INPUT_BASE,
+ ...EXAMPLE_FIELD_1_WITH_ERROR_FALSE,
+};
+
describe('macro: duration', () => {
describe('mode: multiple fields', () => {
it('passes jest-axe checks', async () => {
@@ -109,6 +174,12 @@ describe('macro: duration', () => {
expect($(div).hasClass('ons-field-group')).toBe(true);
});
+ it('has the correct number of inputs', () => {
+ const $ = cheerio.load(renderComponent('duration', EXAMPLE_DURATION_MULTIPLE_FIELDS));
+ const $inputs = $('.ons-input');
+ expect($inputs.length).toBe(2);
+ });
+
it('has the expected `fieldset` output', () => {
const faker = templateFaker();
const fieldsetSpy = faker.spy('fieldset');
@@ -141,10 +212,11 @@ describe('macro: duration', () => {
mutuallyExclusive: {
legendClasses: 'custom-legend-class',
dontWrap: true,
+ classes: undefined,
legendIsQuestionTitle: true,
error: false,
mutuallyExclusive: {
- checkbox: {},
+ exclusiveOptions: {},
or: 'Or',
deselectMessage: 'Deselect message',
deselectGroupAdjective: 'Deselect group adjective',
@@ -166,10 +238,10 @@ describe('macro: duration', () => {
...EXAMPLE_DURATION_MULTIPLE_FIELDS,
legendClasses: 'custom-legend-class',
dontWrap: true,
+ classes: undefined,
legendIsQuestionTitle: true,
error: false,
mutuallyExclusive: {
- checkbox: {},
or: 'Or',
deselectMessage: 'Deselect message',
deselectGroupAdjective: 'Deselect group adjective',
@@ -183,9 +255,9 @@ describe('macro: duration', () => {
description: 'Enter “0” into the years field if you have lived at this address for less than a year',
legendClasses: 'custom-legend-class',
dontWrap: true,
+ classes: undefined,
legendIsQuestionTitle: true,
error: false,
- checkbox: {},
or: 'Or',
deselectMessage: 'Deselect message',
deselectGroupAdjective: 'Deselect group adjective',
@@ -215,7 +287,6 @@ describe('macro: duration', () => {
classes: '',
value: '0',
attributes: undefined,
- classes: '',
error: undefined,
fieldId: 'duration',
label: {
@@ -226,10 +297,17 @@ describe('macro: duration', () => {
suffix: {
id: 'address-duration-years-suffix',
text: 'Years',
+ title: undefined,
},
});
});
+ it('has the correct number of inputs', () => {
+ const $ = cheerio.load(renderComponent('duration', EXAMPLE_DURATION_SINGLE_FIELD));
+ const $inputs = $('.ons-input');
+ expect($inputs.length).toBe(1);
+ });
+
it('has the expected `error` output', () => {
const faker = templateFaker();
const errorSpy = faker.spy('error');
@@ -244,4 +322,34 @@ describe('macro: duration', () => {
});
});
});
+
+ describe('mode: multiple fields with errors', () => {
+ it('passes jest-axe checks', async () => {
+ const $ = cheerio.load(renderComponent('duration', EXAMPLE_DURATION_MULTIPLE_FIELDS_WITH_SINGLE_ERROR));
+
+ const results = await axe($.html());
+ expect(results).toHaveNoViolations();
+ });
+
+ it('has the provided error class on one input', async () => {
+ const $ = cheerio.load(renderComponent('duration', EXAMPLE_DURATION_MULTIPLE_FIELDS_WITH_SINGLE_ERROR));
+ const $errorContent = $('.ons-input--error');
+
+ expect($errorContent.length).toBe(1);
+ });
+
+ it('has the provided error class on multiple inputs', async () => {
+ const $ = cheerio.load(renderComponent('duration', EXAMPLE_DURATION_MULTIPLE_FIELDS_WITH_ERROR));
+ const $errorContent = $('.ons-input--error');
+
+ expect($errorContent.length).toBe(2);
+ });
+
+ it('does not provide error class when error parameter set to false', async () => {
+ const $ = cheerio.load(renderComponent('duration', EXAMPLE_DURATION_MULTIPLE_FIELDS_WITH_ERROR_FALSE));
+ const $errorContent = $('.ons-input--error');
+
+ expect($errorContent.length).toBe(0);
+ });
+ });
});
diff --git a/src/components/duration/example-duration-single-field.njk b/src/components/duration/example-duration-single-field.njk
new file mode 100644
index 0000000000..001b340e9a
--- /dev/null
+++ b/src/components/duration/example-duration-single-field.njk
@@ -0,0 +1,24 @@
+{% from "components/question/_macro.njk" import onsQuestion %}
+{% from "components/duration/_macro.njk" import onsDuration %}
+
+{% call onsQuestion({
+ "title": "How many years have you lived at this address?",
+ "description": "Enter “0” into the years field if you have lived at this address for less than a year
",
+ "legendIsQuestionTitle": true
+}) %}
+ {{ onsDuration({
+ "id": "address-duration-example-single",
+ "dontWrap": true,
+ "field1": {
+ "id": "address-duration-years-example",
+ "name": "address-duration-years",
+ "suffix": {
+ "text": "Years",
+ "id": "address-duration-years-suffix-example"
+ },
+ "attributes": {
+ "autocomplete": "off"
+ }
+ }
+ }) }}
+{% endcall %}
diff --git a/src/components/metadata/_macro.njk b/src/components/metadata/_macro.njk
index ea4a0f2c0a..5f11c923ac 100644
--- a/src/components/metadata/_macro.njk
+++ b/src/components/metadata/_macro.njk
@@ -1,14 +1,14 @@
{% from "components/description-list/_macro.njk" import onsDescriptionList %}
{% macro onsMetadata(params) %}
-{{
- onsDescriptionList({
- "id": params.id,
- "classes": params.classes,
- "descriptionListLabel": params.metadataLabel,
- "termCol": params.termCol,
- "descriptionCol": params.descriptionCol,
- "itemsList": params.itemsList
- })
-}}
+ {{
+ onsDescriptionList({
+ "id": params.id,
+ "classes": params.classes,
+ "descriptionListLabel": params.metadataLabel,
+ "termCol": params.termCol,
+ "descriptionCol": params.descriptionCol,
+ "itemsList": params.itemsList
+ })
+ }}
{% endmacro %}
diff --git a/src/components/multiple-input-fields/_macro.njk b/src/components/multiple-input-fields/_macro.njk
new file mode 100644
index 0000000000..aeae347571
--- /dev/null
+++ b/src/components/multiple-input-fields/_macro.njk
@@ -0,0 +1,49 @@
+{% from "components/mutually-exclusive/_macro.njk" import onsMutuallyExclusive %}
+{% from "components/fieldset/_macro.njk" import onsFieldset %}
+
+{% macro onsMultipleInputFields(params) %}
+ {% if params.numberOfFields > 1 %}
+ {% set fields %}
+
+ {{ params.fields | safe }}
+
+ {% endset %}
+ {% else %}
+ {{ params.fields | safe }}
+ {% endif %}
+
+ {% if params.mutuallyExclusive %}
+ {% call onsMutuallyExclusive({
+ "id": params.id,
+ "legend": params.legendOrLabel,
+ "legendClasses": params.legendClasses,
+ "description": params.description,
+ "classes": params.classes,
+ "dontWrap": params.dontWrap if params.numberOfFields > 1 else true,
+ "legendIsQuestionTitle": params.legendIsQuestionTitle,
+ "exclusiveOptions": params.mutuallyExclusive.exclusiveOptions,
+ "or": params.mutuallyExclusive.or,
+ "deselectMessage": params.mutuallyExclusive.deselectMessage,
+ "deselectGroupAdjective": params.mutuallyExclusive.deselectGroupAdjective,
+ "deselectExclusiveOptionAdjective": params.mutuallyExclusive.deselectExclusiveOptionAdjective,
+ "error": params.error
+ }) %}
+ {{ fields | safe }}
+ {% endcall %}
+ {% elif params.numberOfFields > 1 %}
+ {% call onsFieldset({
+ "id": params.id,
+ "legend": params.legendOrLabel,
+ "legendClasses": params.legendClasses,
+ "description": params.description,
+ "classes": params.classes,
+ "dontWrap": params.dontWrap,
+ "legendIsQuestionTitle": params.legendIsQuestionTitle,
+ "error": params.error
+ }) %}
+ {{ fields | safe }}
+ {% endcall %}
+ {% else %}
+ {{ fields | safe }}
+ {% endif %}
+{% endmacro %}