@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 +1 -1
- package/src/components/select/index.njk +22 -18
- package/src/components/select/question.js +5 -0
- package/src/components/select/question.test.js +77 -1
- package/src/questions/question-props.d.ts +1 -0
- package/test/snapshots/travel-class.html +17 -17
- package/types/src/components/select/question.d.ts +4 -1
- package/types/src/components/select/question.d.ts.map +1 -1
- package/types/src/questions/question-props.d.ts +1 -0
package/package.json
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
5
5
|
|
|
6
6
|
{% block head %}
|
|
7
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
if
|
|
67
|
-
accessibleAutocomplete
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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;
|
|
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 & {
|