@planning-inspectorate/dynamic-forms 3.8.3 → 3.9.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planning-inspectorate/dynamic-forms",
3
- "version": "3.8.3",
3
+ "version": "3.9.0",
4
4
  "description": "This package is for building GDS forms using a configuration-based approach.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -4,7 +4,9 @@
4
4
  {% from "govuk/components/button/macro.njk" import govukButton %}
5
5
 
6
6
  {% block head %}
7
- <link rel="stylesheet" href="/assets/css/accessible-autocomplete.min.css"/>
7
+ {% if not question.disableAccessibleAutocomplete %}
8
+ <link rel="stylesheet" href="/assets/css/accessible-autocomplete.min.css"/>
9
+ {% endif %}
8
10
 
9
11
  {{ super() }}
10
12
  {% endblock %}
@@ -61,22 +63,24 @@
61
63
  </form>
62
64
  </div>
63
65
  </div>
64
- <script src="/assets/js/accessible-autocomplete.min.js"></script>
65
- <script {% if cspNonce %}nonce={{ cspNonce }}{% endif %}>
66
- if (window.accessibleAutocomplete) {
67
- accessibleAutocomplete.enhanceSelectElement({
68
- selectElement: document.querySelector('#{{ question.fieldName }}'),
69
- onConfirm: () => {
70
- let input = document.querySelector('#{{ question.fieldName }}');
71
- let select = document.querySelector('#{{ question.fieldName }}-select');
72
- let options = Array.from(select.options);
73
- if (!input.value || !options.some(option => option.innerText === input.value)) {
74
- select.options.selectedIndex = -1;
75
- } else {
76
- select.options.selectedIndex = options.findIndex(option => option.innerText === input.value);
66
+ {% if not question.disableAccessibleAutocomplete %}
67
+ <script src="/assets/js/accessible-autocomplete.min.js"></script>
68
+ <script {% if cspNonce %}nonce={{ cspNonce }}{% endif %}>
69
+ if (window.accessibleAutocomplete) {
70
+ accessibleAutocomplete.enhanceSelectElement({
71
+ selectElement: document.querySelector('#{{ question.fieldName }}'),
72
+ onConfirm: () => {
73
+ let input = document.querySelector('#{{ question.fieldName }}');
74
+ let select = document.querySelector('#{{ question.fieldName }}-select');
75
+ let options = Array.from(select.options);
76
+ if (!input.value || !options.some(option => option.innerText === input.value)) {
77
+ select.options.selectedIndex = -1;
78
+ } else {
79
+ select.options.selectedIndex = options.findIndex(option => option.innerText === input.value);
80
+ }
77
81
  }
78
- }
79
- })
80
- }
81
- </script>
82
+ })
83
+ }
84
+ </script>
85
+ {% endif %}
82
86
  {% endblock %}
@@ -1,6 +1,7 @@
1
1
  import OptionsQuestion from '../../questions/options-question.js';
2
2
 
3
3
  export default class SelectQuestion extends OptionsQuestion {
4
+ #disableAccessibleAutocomplete;
4
5
  /**
5
6
  * @param {Object} params
6
7
  * @param {string} params.title
@@ -14,6 +15,7 @@ export default class SelectQuestion extends OptionsQuestion {
14
15
  * @param {string} [params.label]
15
16
  * @param {string} [params.html]
16
17
  * @param {string} [params.legend] - optional legend, used instead of h1
18
+ * @param {string} [params.disableAccessibleAutocomplete]
17
19
  * @param {Array.<import('../../questions/options-question.js').Option>} params.options
18
20
  * @param {Object<string, any>} [params.viewData]
19
21
  * @param {Array.<import('#base-validator').BaseValidator>} [params.validators]
@@ -30,6 +32,7 @@ export default class SelectQuestion extends OptionsQuestion {
30
32
  label,
31
33
  html,
32
34
  legend,
35
+ disableAccessibleAutocomplete,
33
36
  options,
34
37
  validators,
35
38
  viewData
@@ -51,6 +54,7 @@ export default class SelectQuestion extends OptionsQuestion {
51
54
  this.html = html;
52
55
  this.label = label;
53
56
  this.legend = legend;
57
+ this.#disableAccessibleAutocomplete = disableAccessibleAutocomplete;
54
58
  }
55
59
 
56
60
  /**
@@ -59,6 +63,7 @@ export default class SelectQuestion extends OptionsQuestion {
59
63
  addCustomDataToViewModel(viewModel) {
60
64
  viewModel.question.label = this.label;
61
65
  viewModel.question.legend = this.legend;
66
+ viewModel.question.disableAccessibleAutocomplete = this.#disableAccessibleAutocomplete;
62
67
  }
63
68
 
64
69
  /**
@@ -1,8 +1,9 @@
1
- import { describe, it } from 'node:test';
1
+ import { describe, it, mock } from 'node:test';
2
2
  import assert from 'node:assert';
3
3
  import ValidOptionValidator from '../../validator/valid-option-validator.js';
4
4
  import SelectQuestion from './question.js';
5
5
  import nunjucks from 'nunjucks';
6
+ import { configureNunjucksTestEnv } from '#test/utils/nunjucks.js';
6
7
 
7
8
  const TITLE = 'Select question';
8
9
  const QUESTION = 'A select question';
@@ -94,6 +95,81 @@ describe('./src/dynamic-forms/components/select/question.js', () => {
94
95
  assert.strictEqual(preppedQuestion.question.label, LABEL);
95
96
  });
96
97
 
98
+ it('should pass in disableAccessibleAutocomplete property to view', (ctx) => {
99
+ nunjucks.render = ctx.mock.fn();
100
+ nunjucks.render.mock.mockImplementation(() => {});
101
+
102
+ const selectQuestion = new SelectQuestion({
103
+ title: TITLE,
104
+ question: QUESTION,
105
+ description: DESCRIPTION,
106
+ fieldName: FIELDNAME,
107
+ html: HTML,
108
+ label: LABEL,
109
+ options: OPTIONS,
110
+ disableAccessibleAutocomplete: true
111
+ });
112
+
113
+ const customViewData = { hello: 'hi' };
114
+
115
+ const preppedQuestion = selectQuestion.prepQuestionForRendering(SECTION, JOURNEY, customViewData);
116
+
117
+ assert.strictEqual(preppedQuestion.question.disableAccessibleAutocomplete, true);
118
+ });
119
+
120
+ it('should include accessible autocomplete by default', async () => {
121
+ const selectQuestion = new SelectQuestion({
122
+ title: TITLE,
123
+ question: QUESTION,
124
+ description: DESCRIPTION,
125
+ fieldName: FIELDNAME,
126
+ html: HTML,
127
+ label: LABEL,
128
+ options: OPTIONS
129
+ });
130
+ const viewModel = selectQuestion.prepQuestionForRendering(SECTION, JOURNEY, {
131
+ layoutTemplate: 'views/layout-journey.njk'
132
+ });
133
+
134
+ const nunjucks = configureNunjucksTestEnv();
135
+ const mockRes = {
136
+ render: mock.fn((view, data) => nunjucks.render(view + '.njk', data))
137
+ };
138
+ selectQuestion.renderAction(mockRes, viewModel);
139
+
140
+ assert.strictEqual(mockRes.render.mock.callCount(), 1);
141
+ const view = mockRes.render.mock.calls[0].result;
142
+ assert.ok(view);
143
+ assert.match(view, /accessible-autocomplete\.min\.js/);
144
+ });
145
+
146
+ it('should not include accessible autocomplete if configured', async () => {
147
+ const selectQuestion = new SelectQuestion({
148
+ title: TITLE,
149
+ question: QUESTION,
150
+ description: DESCRIPTION,
151
+ fieldName: FIELDNAME,
152
+ html: HTML,
153
+ label: LABEL,
154
+ options: OPTIONS,
155
+ disableAccessibleAutocomplete: true
156
+ });
157
+ const viewModel = selectQuestion.prepQuestionForRendering(SECTION, JOURNEY, {
158
+ layoutTemplate: 'views/layout-journey.njk'
159
+ });
160
+
161
+ const nunjucks = configureNunjucksTestEnv();
162
+ const mockRes = {
163
+ render: mock.fn((view, data) => nunjucks.render(view + '.njk', data))
164
+ };
165
+ selectQuestion.renderAction(mockRes, viewModel);
166
+
167
+ assert.strictEqual(mockRes.render.mock.callCount(), 1);
168
+ const view = mockRes.render.mock.calls[0].result;
169
+ assert.ok(view);
170
+ assert.doesNotMatch(view, /accessible-autocomplete\.min\.js/);
171
+ });
172
+
97
173
  it('should add selected attribute to chosen option', (ctx) => {
98
174
  nunjucks.render = ctx.mock.fn();
99
175
  nunjucks.render.mock.mockImplementation(() => {});
@@ -129,6 +129,7 @@ type RadioQuestionProps = CommonQuestionProps & {
129
129
  type SelectQuestionProps = CommonQuestionProps & {
130
130
  type: 'select';
131
131
  options: Option[];
132
+ disableAccessibleAutocomplete?: boolean;
132
133
  };
133
134
 
134
135
  type SingleLineInputQuestionProps = CommonQuestionProps & {
@@ -26,21 +26,21 @@
26
26
  </form>
27
27
  </div>
28
28
  </div>
29
- <script src="/assets/js/accessible-autocomplete.min.js"></script>
30
- <script >
31
- if (window.accessibleAutocomplete) {
32
- accessibleAutocomplete.enhanceSelectElement({
33
- selectElement: document.querySelector('#travelClass'),
34
- onConfirm: () => {
35
- let input = document.querySelector('#travelClass');
36
- let select = document.querySelector('#travelClass-select');
37
- let options = Array.from(select.options);
38
- if (!input.value || !options.some(option => option.innerText === input.value)) {
39
- select.options.selectedIndex = -1;
40
- } else {
41
- select.options.selectedIndex = options.findIndex(option => option.innerText === input.value);
29
+ <script src="/assets/js/accessible-autocomplete.min.js"></script>
30
+ <script >
31
+ if (window.accessibleAutocomplete) {
32
+ accessibleAutocomplete.enhanceSelectElement({
33
+ selectElement: document.querySelector('#travelClass'),
34
+ onConfirm: () => {
35
+ let input = document.querySelector('#travelClass');
36
+ let select = document.querySelector('#travelClass-select');
37
+ let options = Array.from(select.options);
38
+ if (!input.value || !options.some(option => option.innerText === input.value)) {
39
+ select.options.selectedIndex = -1;
40
+ } else {
41
+ select.options.selectedIndex = options.findIndex(option => option.innerText === input.value);
42
+ }
42
43
  }
43
- }
44
- })
45
- }
46
- </script>
44
+ })
45
+ }
46
+ </script>
@@ -12,11 +12,12 @@ export default class SelectQuestion extends OptionsQuestion {
12
12
  * @param {string} [params.label]
13
13
  * @param {string} [params.html]
14
14
  * @param {string} [params.legend] - optional legend, used instead of h1
15
+ * @param {string} [params.disableAccessibleAutocomplete]
15
16
  * @param {Array.<import('../../questions/options-question.js').Option>} params.options
16
17
  * @param {Object<string, any>} [params.viewData]
17
18
  * @param {Array.<import('#base-validator').BaseValidator>} [params.validators]
18
19
  */
19
- constructor({ title, question, fieldName, viewFolder, url, hint, pageTitle, description, label, html, legend, options, validators, viewData }: {
20
+ constructor({ title, question, fieldName, viewFolder, url, hint, pageTitle, description, label, html, legend, disableAccessibleAutocomplete, options, validators, viewData }: {
20
21
  title: string;
21
22
  question: string;
22
23
  fieldName: string;
@@ -28,6 +29,7 @@ export default class SelectQuestion extends OptionsQuestion {
28
29
  label?: string | undefined;
29
30
  html?: string | undefined;
30
31
  legend?: string | undefined;
32
+ disableAccessibleAutocomplete?: string | undefined;
31
33
  options: Array<import("../../questions/options-question.js").Option>;
32
34
  viewData?: {
33
35
  [x: string]: any;
@@ -46,6 +48,7 @@ export default class SelectQuestion extends OptionsQuestion {
46
48
  * @returns {Array.<Object>}
47
49
  */
48
50
  formatAnswerForSummary(sectionSegment: string, journey: Journey, answer: Object): Array<Object>;
51
+ #private;
49
52
  }
50
53
  import OptionsQuestion from '../../questions/options-question.js';
51
54
  //# sourceMappingURL=question.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"question.d.ts","sourceRoot":"","sources":["../../../../src/components/select/question.js"],"names":[],"mappings":"AAEA;IACC;;;;;;;;;;;;;;;;OAgBG;IACH,+IAfG;QAAuB,KAAK,EAApB,MAAM;QACS,QAAQ,EAAvB,MAAM;QACS,SAAS,EAAxB,MAAM;QACU,UAAU;QACV,GAAG;QACH,IAAI;QACJ,SAAS;QACT,WAAW;QACX,KAAK;QACL,IAAI;QACJ,MAAM;QAC+C,OAAO,EAA5E,KAAK,CAAE,OAAO,qCAAqC,EAAE,MAAM,CAAC;QAC/B,QAAQ;;;QACoB,UAAU;KAAC,EAmC9E;IAFA,0BAAkB;IAClB,2BAAoB;IAWrB;;;;;;;;OAQG;IACH,wDAJW,OAAO,UADP,MAAM,GAGJ,KAAK,CAAE,MAAM,CAAC,CAS1B;CACD;4BAhF2B,qCAAqC"}
1
+ {"version":3,"file":"question.d.ts","sourceRoot":"","sources":["../../../../src/components/select/question.js"],"names":[],"mappings":"AAEA;IAEC;;;;;;;;;;;;;;;;;OAiBG;IACH,8KAhBG;QAAuB,KAAK,EAApB,MAAM;QACS,QAAQ,EAAvB,MAAM;QACS,SAAS,EAAxB,MAAM;QACU,UAAU;QACV,GAAG;QACH,IAAI;QACJ,SAAS;QACT,WAAW;QACX,KAAK;QACL,IAAI;QACJ,MAAM;QACN,6BAA6B;QACwB,OAAO,EAA5E,KAAK,CAAE,OAAO,qCAAqC,EAAE,MAAM,CAAC;QAC/B,QAAQ;;;QACoB,UAAU;KAAC,EAqC9E;IAHA,0BAAkB;IAClB,2BAAoB;IAarB;;;;;;;;OAQG;IACH,wDAJW,OAAO,UADP,MAAM,GAGJ,KAAK,CAAE,MAAM,CAAC,CAS1B;;CACD;4BArF2B,qCAAqC"}
@@ -129,6 +129,7 @@ type RadioQuestionProps = CommonQuestionProps & {
129
129
  type SelectQuestionProps = CommonQuestionProps & {
130
130
  type: 'select';
131
131
  options: Option[];
132
+ disableAccessibleAutocomplete?: boolean;
132
133
  };
133
134
 
134
135
  type SingleLineInputQuestionProps = CommonQuestionProps & {