@ons/design-system 72.10.7 → 72.10.9
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/components/accordion/accordion.js +3 -2
- package/components/autosuggest/autosuggest.spec.js +2 -0
- package/components/autosuggest/autosuggest.ui.js +12 -7
- package/components/breadcrumbs/_breadcrumbs.scss +53 -0
- package/components/breadcrumbs/_macro.njk +33 -24
- package/components/breadcrumbs/_macro.spec.js +25 -0
- package/components/chart/_chart.scss +91 -0
- package/components/chart/_macro.njk +38 -7
- package/components/chart/_macro.spec.js +102 -13
- package/components/chart/bar-chart.js +9 -1
- package/components/chart/chart-iframe-resize.js +1 -1
- package/components/chart/chart.dom.js +5 -3
- package/components/chart/chart.js +8 -2
- package/components/chart/common-chart-options.js +9 -0
- package/components/chart/example-area-chart.njk +2 -1
- package/components/chart/example-bar-chart-with-axis-min-and-max-values.njk +0 -1
- package/components/chart/example-bar-chart-with-point-range-and-reference-line-annotations.njk +4 -4
- package/components/chart/example-bar-chart.njk +0 -1
- package/components/chart/example-iframe-chart.njk +2 -1
- package/components/chart/example-line-chart.njk +2 -1
- package/components/chart/range-annotations-options.js +1 -1
- package/components/download-resources/download-resources.spec.js +2 -0
- package/components/hero/_hero.scss +17 -22
- package/components/hero/_macro.njk +1 -1
- package/components/hero/_macro.spec.js +1 -1
- package/components/hero/example-hero-dark-with-external-breadcrumbs.njk +194 -0
- package/components/hero/example-hero-default-with-external-breadcrumbs.njk +201 -0
- package/components/hero/example-hero-grey-with-external-breadcrumbs.njk +243 -0
- package/components/hero/example-hero-navy-blue-with-external-breadcrumbs.njk +200 -0
- package/components/hero/example-hero-pale-blue-with-external-breadcrumbs.njk +201 -0
- package/components/icon/_macro.njk +1 -1
- package/components/mutually-exclusive/mutually-exclusive.js +3 -1
- package/components/radios/clear-radios.js +4 -2
- package/components/relationships/relationships.js +4 -2
- package/components/tabs/tabs.js +2 -2
- package/components/video/video.js +2 -0
- package/css/main.css +1 -1
- package/img/small/area-chart-screenshot.png +0 -0
- package/img/small/line-chart-screenshot.png +0 -0
- package/js/timeout.js +9 -6
- package/layout/_template.njk +4 -1
- package/package.json +7 -5
- package/scripts/main.es5.js +4 -2
- package/scripts/main.js +4 -2
- package/scss/objects/_page.scss +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import DOMPurify from 'dompurify';
|
|
1
2
|
export default class Accordion {
|
|
2
3
|
constructor(button, detailsEls) {
|
|
3
4
|
this.openDetailsEls = 0;
|
|
@@ -52,11 +53,11 @@ export default class Accordion {
|
|
|
52
53
|
|
|
53
54
|
setButton() {
|
|
54
55
|
if (this.canClose()) {
|
|
55
|
-
this.buttonInner.innerHTML = this.closeButton;
|
|
56
|
+
this.buttonInner.innerHTML = DOMPurify.sanitize(this.closeButton);
|
|
56
57
|
this.button.setAttribute('data-ga-label', this.buttonOpen);
|
|
57
58
|
this.button.setAttribute('aria-expanded', 'true');
|
|
58
59
|
} else {
|
|
59
|
-
this.buttonInner.innerHTML = this.buttonOpen;
|
|
60
|
+
this.buttonInner.innerHTML = DOMPurify.sanitize(this.buttonOpen);
|
|
60
61
|
this.button.setAttribute('data-ga-label', this.closeButton);
|
|
61
62
|
this.button.setAttribute('aria-expanded', 'false');
|
|
62
63
|
}
|
|
@@ -386,9 +386,11 @@ describe('script: autosuggest', () => {
|
|
|
386
386
|
describe('when the mouse moves over a result and a suggestion is focused', () => {
|
|
387
387
|
it('removes the focused class', async () => {
|
|
388
388
|
await setTestPage('/test', renderComponent('autosuggest', EXAMPLE_AUTOSUGGEST));
|
|
389
|
+
await page.mouse.move(0, 0); // move out of the component
|
|
389
390
|
|
|
390
391
|
await page.type('.ons-js-autosuggest-input', 'state', { delay: 20 });
|
|
391
392
|
await page.keyboard.press('ArrowDown');
|
|
393
|
+
|
|
392
394
|
await page.hover('.ons-autosuggest__option:nth-child(2)');
|
|
393
395
|
|
|
394
396
|
const focusedClassCount = await page.$$eval('.ons-autosuggest__option--focused', (nodes) => nodes.length);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import abortableFetch from '../../js/abortable-fetch';
|
|
2
2
|
import { sanitiseAutosuggestText } from './autosuggest.helpers';
|
|
3
3
|
import runFuse from './fuse-config';
|
|
4
|
+
import DOMPurify from 'dompurify';
|
|
4
5
|
|
|
5
6
|
export const baseClass = 'ons-js-autosuggest';
|
|
6
7
|
|
|
@@ -398,7 +399,7 @@ export default class AutosuggestUI {
|
|
|
398
399
|
const listElement = document.createElement('li');
|
|
399
400
|
listElement.className = `${classAutosuggestOption} ${classAutosuggestOptionMoreResults}`;
|
|
400
401
|
listElement.setAttribute('aria-hidden', 'true');
|
|
401
|
-
listElement.innerHTML = this.moreResults;
|
|
402
|
+
listElement.innerHTML = DOMPurify.sanitize(this.moreResults);
|
|
402
403
|
this.listbox.appendChild(listElement);
|
|
403
404
|
}
|
|
404
405
|
|
|
@@ -436,10 +437,12 @@ export default class AutosuggestUI {
|
|
|
436
437
|
if (status === 400 || status === false) {
|
|
437
438
|
message = this.typeMore;
|
|
438
439
|
this.setAriaStatus(message);
|
|
439
|
-
this.listbox.innerHTML =
|
|
440
|
+
this.listbox.innerHTML = DOMPurify.sanitize(
|
|
441
|
+
`<li class="${classAutosuggestOption} ${classAutosuggestOptionNoResults}">${message}</li>`,
|
|
442
|
+
);
|
|
440
443
|
} else if (status > 400 || status === '') {
|
|
441
|
-
|
|
442
|
-
|
|
444
|
+
const sanitizedHref = DOMPurify.sanitize(window.location.href);
|
|
445
|
+
message = this.errorAPI + (this.errorAPILinkText ? ' <a href="' + sanitizedHref + '">' + this.errorAPILinkText + '</a>.' : '');
|
|
443
446
|
let ariaMessage = this.errorAPI + (this.errorAPILinkText ? ' ' + this.errorAPILinkText : '');
|
|
444
447
|
|
|
445
448
|
this.input.setAttribute('disabled', true);
|
|
@@ -453,7 +456,9 @@ export default class AutosuggestUI {
|
|
|
453
456
|
this.resultsTitleContainer.remove();
|
|
454
457
|
} else {
|
|
455
458
|
message = this.noResults;
|
|
456
|
-
this.listbox.innerHTML =
|
|
459
|
+
this.listbox.innerHTML = DOMPurify.sanitize(
|
|
460
|
+
`<li class="${classAutosuggestOption} ${classAutosuggestOptionNoResults}">${message}</li>`,
|
|
461
|
+
);
|
|
457
462
|
}
|
|
458
463
|
}
|
|
459
464
|
|
|
@@ -503,7 +508,7 @@ export default class AutosuggestUI {
|
|
|
503
508
|
}
|
|
504
509
|
}
|
|
505
510
|
}
|
|
506
|
-
this.ariaStatus.innerHTML = content;
|
|
511
|
+
this.ariaStatus.innerHTML = DOMPurify.sanitize(content);
|
|
507
512
|
}
|
|
508
513
|
|
|
509
514
|
selectResult(index) {
|
|
@@ -548,7 +553,7 @@ export default class AutosuggestUI {
|
|
|
548
553
|
warningSpanElement.innerHTML = '!';
|
|
549
554
|
|
|
550
555
|
warningBodyElement.className = 'ons-panel__body';
|
|
551
|
-
warningBodyElement.innerHTML = content;
|
|
556
|
+
warningBodyElement.innerHTML = DOMPurify.sanitize(content);
|
|
552
557
|
|
|
553
558
|
warningElement.appendChild(warningSpanElement);
|
|
554
559
|
warningElement.appendChild(warningBodyElement);
|
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
$breadcrumb-chevron-height: 0.65rem;
|
|
2
2
|
|
|
3
|
+
.ons-breadcrumbs-wrapper {
|
|
4
|
+
position: relative;
|
|
5
|
+
z-index: 10;
|
|
6
|
+
margin-bottom: -2rem;
|
|
7
|
+
&--grey {
|
|
8
|
+
background-color: var(--ons-color-banner-bg);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&--dark {
|
|
12
|
+
background-color: var(--ons-color-hero-bg-dark);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&--navy-blue {
|
|
16
|
+
background-color: var(--ons-color-navy-blue-light);
|
|
17
|
+
margin-bottom: -1.75rem;
|
|
18
|
+
@include mq(l) {
|
|
19
|
+
margin-bottom: -3.25rem;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&--dark,
|
|
24
|
+
&--navy-blue {
|
|
25
|
+
.ons-icon {
|
|
26
|
+
color: var(--ons-color-text-inverse);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.ons-breadcrumbs__link {
|
|
30
|
+
color: var(--ons-color-text-inverse);
|
|
31
|
+
text-decoration: underline;
|
|
32
|
+
|
|
33
|
+
&:hover {
|
|
34
|
+
color: var(--ons-color-text-inverse);
|
|
35
|
+
text-decoration: underline solid var(--ons-color-text-inverse) 2px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&:focus {
|
|
39
|
+
color: var(--ons-color-text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&:focus:hover {
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&--pale-blue {
|
|
49
|
+
background-color: var(--ons-color-pale-blue);
|
|
50
|
+
}
|
|
51
|
+
.ons-breadcrumbs {
|
|
52
|
+
padding: 1rem;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
3
56
|
.ons-breadcrumbs {
|
|
4
57
|
align-items: center;
|
|
5
58
|
display: flex;
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
{% from "components/icon/_macro.njk" import onsIcon %}
|
|
2
|
-
|
|
3
2
|
{% macro onsBreadcrumbs(params) %}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<
|
|
13
|
-
class="ons-
|
|
14
|
-
|
|
15
|
-
{% if item.id %}{{ ' ' }}id='{{ item.id }}'{% endif %}
|
|
16
|
-
{% if item.attributes %}{% for attribute, value in (item.attributes.items() if item.attributes is mapping and item.attributes.items else item.attributes) %}{{ ' ' }}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
|
|
17
|
-
>{{ item.text }}</a
|
|
3
|
+
{% set breadcrumbs %}
|
|
4
|
+
<nav
|
|
5
|
+
class="ons-breadcrumbs{{ ' ons-container' if params.variant }}{{ ' ' + params.classes if params.classes else '' }}"
|
|
6
|
+
aria-label="{{ params.ariaLabel | default('Breadcrumbs') }}"
|
|
7
|
+
{% if params.id %}id="{{ params.id }}"{% endif %}
|
|
8
|
+
>
|
|
9
|
+
<ol class="ons-breadcrumbs__items ons-u-fs-s">
|
|
10
|
+
{%- for item in params.itemsList -%}
|
|
11
|
+
<li
|
|
12
|
+
class="ons-breadcrumbs__item{{ ' ' + item.itemClasses if item.itemClasses else '' }}"
|
|
13
|
+
id="breadcrumb-{{ loop.index }}"
|
|
18
14
|
>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
<a
|
|
16
|
+
class="ons-breadcrumbs__link{{ ' ' + item.linkClasses if item.linkClasses else '' }}"
|
|
17
|
+
href="{% if not isDesignSystemExample %}{{ item.url }}{% else %}#0{% endif %}"
|
|
18
|
+
{% if item.id %}{{ ' ' }}id='{{ item.id }}'{% endif %}
|
|
19
|
+
{% if item.attributes %}{% for attribute, value in (item.attributes.items() if item.attributes is mapping and item.attributes.items else item.attributes) %}{{ ' ' }}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
|
|
20
|
+
>{{ item.text }}</a
|
|
21
|
+
>
|
|
22
|
+
{{-
|
|
23
|
+
onsIcon({
|
|
24
|
+
"iconType": "chevron"
|
|
25
|
+
})
|
|
26
|
+
-}}
|
|
27
|
+
</li>
|
|
28
|
+
{%- endfor -%}
|
|
29
|
+
</ol>
|
|
30
|
+
</nav>
|
|
31
|
+
{% endset %}
|
|
32
|
+
{% if params.variant %}
|
|
33
|
+
<div class="ons-breadcrumbs-wrapper ons-breadcrumbs-wrapper--{{ params.variant }}">{{ breadcrumbs | safe }}</div>
|
|
34
|
+
{% else %}
|
|
35
|
+
{{ breadcrumbs | safe }}
|
|
36
|
+
{% endif %}
|
|
28
37
|
{% endmacro %}
|
|
@@ -132,4 +132,29 @@ describe('FOR: Macro: Breadcrumbs', () => {
|
|
|
132
132
|
});
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
|
+
|
|
136
|
+
describe('GIVEN: Params: variant', () => {
|
|
137
|
+
describe('WHEN: variant is provided', () => {
|
|
138
|
+
const $ = cheerio.load(
|
|
139
|
+
renderComponent('breadcrumbs', {
|
|
140
|
+
...EXAMPLE_BREADCRUMBS_REQUIRED_PARAMS,
|
|
141
|
+
variant: 'grey',
|
|
142
|
+
}),
|
|
143
|
+
);
|
|
144
|
+
test('THEN: renders breadcrumbs in a breadcrumbs-wrapper with correct modifier class', () => {
|
|
145
|
+
expect($('.ons-breadcrumbs-wrapper').hasClass('ons-breadcrumbs-wrapper--grey')).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('WHEN: variant is not provided', () => {
|
|
150
|
+
const $ = cheerio.load(
|
|
151
|
+
renderComponent('breadcrumbs', {
|
|
152
|
+
...EXAMPLE_BREADCRUMBS_REQUIRED_PARAMS,
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
test('THEN: does not render breadcrumbs-wrapper', () => {
|
|
156
|
+
expect($('.ons-breadcrumbs-wrapper').length).toBe(0);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
135
160
|
});
|
|
@@ -7,6 +7,28 @@
|
|
|
7
7
|
overflow: visible !important;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
@media (forced-colors: active) {
|
|
11
|
+
.highcharts-plot-band {
|
|
12
|
+
fill: var(--ons-color-grey-75); /* Forces the color used for text in high contrast mode */
|
|
13
|
+
}
|
|
14
|
+
.highcharts-annotation-label text,
|
|
15
|
+
.highcharts-plot-line-label,
|
|
16
|
+
.highcharts-plot-band-label {
|
|
17
|
+
fill: CanvasText !important; /* Forces the color used for text in high contrast mode */
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.highcharts-annotation-label-box {
|
|
21
|
+
fill: Canvas; /* Sets the background to match system background */
|
|
22
|
+
stroke: CanvasText; /* Ensures border is visible in contrast mode */
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&__container:focus {
|
|
27
|
+
box-shadow: 0 0 0 3px var(--ons-color-black);
|
|
28
|
+
outline: 4px solid var(--ons-color-focus);
|
|
29
|
+
outline-offset: 2px;
|
|
30
|
+
}
|
|
31
|
+
|
|
10
32
|
&__download-title {
|
|
11
33
|
@extend .ons-u-pt-l;
|
|
12
34
|
@extend .ons-u-fs-r--b;
|
|
@@ -110,6 +132,12 @@
|
|
|
110
132
|
aspect-ratio: 16 / 9;
|
|
111
133
|
}
|
|
112
134
|
}
|
|
135
|
+
|
|
136
|
+
&__non-js-hide {
|
|
137
|
+
@media (scripting: none) {
|
|
138
|
+
display: none;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
113
141
|
}
|
|
114
142
|
|
|
115
143
|
// This is a workaround to position the axis title to the left
|
|
@@ -164,6 +192,69 @@
|
|
|
164
192
|
border-left: 1px solid var(--ons-color-grey-100);
|
|
165
193
|
}
|
|
166
194
|
|
|
195
|
+
@media (forced-colors: active) {
|
|
196
|
+
.ons-chart__boxplot-legend-item--uncertainty,
|
|
197
|
+
.highcharts-boxplot-box {
|
|
198
|
+
background-color: SelectedItem;
|
|
199
|
+
fill: SelectedItem;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.ons-chart__boxplot-legend-item--estimate,
|
|
203
|
+
.highcharts-boxplot-median {
|
|
204
|
+
background-color: WindowText;
|
|
205
|
+
stroke: WindowText;
|
|
206
|
+
}
|
|
207
|
+
.highcharts-color-0,
|
|
208
|
+
.highcharts-color-0 .highcharts-area,
|
|
209
|
+
.highcharts-legend-item.highcharts-color-0 rect {
|
|
210
|
+
fill: #007faa;
|
|
211
|
+
}
|
|
212
|
+
.highcharts-color-1,
|
|
213
|
+
.highcharts-color-1 .highcharts-area,
|
|
214
|
+
.highcharts-legend-item.highcharts-color-1 rect {
|
|
215
|
+
fill: #a6f0ff;
|
|
216
|
+
}
|
|
217
|
+
.highcharts-color-2,
|
|
218
|
+
.highcharts-color-2 .highcharts-area,
|
|
219
|
+
.highcharts-legend-item.highcharts-color-2 rect {
|
|
220
|
+
fill: #70d49e;
|
|
221
|
+
}
|
|
222
|
+
.highcharts-color-3,
|
|
223
|
+
.highcharts-color-3 .highcharts-area,
|
|
224
|
+
.highcharts-legend-item.highcharts-color-3 rect {
|
|
225
|
+
fill: #e898a5;
|
|
226
|
+
}
|
|
227
|
+
.highcharts-color-4,
|
|
228
|
+
.highcharts-color-4 .highcharts-area,
|
|
229
|
+
.highcharts-legend-item.highcharts-color-4 rect {
|
|
230
|
+
fill: #dadfe1;
|
|
231
|
+
}
|
|
232
|
+
.highcharts-color-5,
|
|
233
|
+
.highcharts-color-5 .highcharts-area,
|
|
234
|
+
.highcharts-legend-item.highcharts-color-5 rect {
|
|
235
|
+
fill: #f9db72;
|
|
236
|
+
}
|
|
237
|
+
.highcharts-color-6,
|
|
238
|
+
.highcharts-color-6 .highcharts-area,
|
|
239
|
+
.highcharts-legend-item.highcharts-color-6 rect {
|
|
240
|
+
fill: #f45b5b;
|
|
241
|
+
}
|
|
242
|
+
.highcharts-color-7,
|
|
243
|
+
.highcharts-color-7 .highcharts-area,
|
|
244
|
+
.highcharts-legend-item.highcharts-color-7 rect {
|
|
245
|
+
fill: #1e824c;
|
|
246
|
+
}
|
|
247
|
+
.highcharts-color-8,
|
|
248
|
+
.highcharts-color-8 .highcharts-area,
|
|
249
|
+
.highcharts-legend-item.highcharts-color-8 rect {
|
|
250
|
+
fill: #e7934c;
|
|
251
|
+
}
|
|
252
|
+
.highcharts-color-9,
|
|
253
|
+
.highcharts-color-9 .highcharts-area,
|
|
254
|
+
.highcharts-legend-item.highcharts-color-9 rect {
|
|
255
|
+
fill: #a0618b;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
167
258
|
// Allow last label to overflow
|
|
168
259
|
.highcharts-container {
|
|
169
260
|
overflow: visible !important;
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
{% set closingSubtitleTag = "</h" ~ (headingLevel + 1) ~ ">" %}
|
|
15
15
|
{% set openingDownloadTitleTag = "<h" ~ (headingLevel + 2) %}
|
|
16
16
|
{% set closingDownloadTitleTag = "</h" ~ (headingLevel + 2) ~ ">" %}
|
|
17
|
+
{% set audioDescriptionId = "chart-audio-description-" ~ params.id %}
|
|
18
|
+
{% set instructionsId = "chart-instructions-" ~ params.id %}
|
|
19
|
+
{% set instructions = params.instructions | default('Use the Tab key to move focus into the chart. Once inside, use the arrow keys to navigate between data points. As you move, tooltips will be announced to describe each point. Touch device users, explore by touch or with swipe gestures.') %}
|
|
20
|
+
|
|
17
21
|
<div
|
|
18
22
|
{% if not params.iframeUrl %}
|
|
19
23
|
data-highcharts-base-chart data-highcharts-type="{{ params.chartType }}" data-highcharts-theme="{{ params.theme }}"
|
|
@@ -48,18 +52,23 @@
|
|
|
48
52
|
{% endif %}
|
|
49
53
|
{% endif %}
|
|
50
54
|
>
|
|
51
|
-
<figure class="ons-chart">
|
|
55
|
+
<figure class="ons-chart" aria-describedby="{{ audioDescriptionId }}">
|
|
52
56
|
{{ openingTitleTag | safe }} class="ons-chart__title">{{ params.title }}{{ closingTitleTag | safe }}
|
|
53
57
|
{% if params.subtitle %}
|
|
54
58
|
{{ openingSubtitleTag | safe }}
|
|
55
59
|
class="ons-chart__subtitle">{{ params.subtitle }}{{ closingSubtitleTag | safe }}
|
|
56
60
|
{% endif %}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
|
|
62
|
+
<p class="ons-u-vh" id="{{ audioDescriptionId }}">{{ params.description }}</p>
|
|
63
|
+
|
|
60
64
|
{% if params.iframeUrl %}
|
|
61
|
-
<div
|
|
62
|
-
|
|
65
|
+
<div
|
|
66
|
+
class="ons-chart__iframe-wrapper{{ ' ons-chart__non-js-hide' if params.fallbackImageUrl else '' }}"
|
|
67
|
+
id="{{ params.id }}"
|
|
68
|
+
data-url="{{ params.iframeUrl }}"
|
|
69
|
+
data-title="{{ params.title }}"
|
|
70
|
+
>
|
|
71
|
+
<iframe src="{{ params.iframeUrl }}" title="{{ params.title }}" class="ons-chart__iframe"></iframe>
|
|
63
72
|
</div>
|
|
64
73
|
{% else %}
|
|
65
74
|
{% if params.chartType == 'boxplot' and (params.estimateLineLabel or params.uncertaintyRangeLabel) and params.legend == true %}
|
|
@@ -79,13 +88,35 @@
|
|
|
79
88
|
</div>
|
|
80
89
|
{% endif %}
|
|
81
90
|
{% if params.chartType in supportedChartTypes %}
|
|
82
|
-
<div
|
|
91
|
+
<div
|
|
92
|
+
data-highcharts-chart-container
|
|
93
|
+
class="ons-chart__container"
|
|
94
|
+
tabindex="0"
|
|
95
|
+
role="region"
|
|
96
|
+
aria-label="chart container"
|
|
97
|
+
aria-describedby="{{ instructionsId }}"
|
|
98
|
+
>
|
|
99
|
+
<div id="{{ instructionsId }}" class="ons-u-vh">{{ instructions }}</div>
|
|
100
|
+
<div data-highcharts-chart class="ons-chart__chart"></div>
|
|
101
|
+
</div>
|
|
83
102
|
{% else %}
|
|
84
103
|
<p data-invalid-chart-type data-unsupported-chart-text>
|
|
85
104
|
<b>{{ '"' + params.chartType + '" - ' + (params.unsupportedChartText or 'chart type is not supported') }}</b>
|
|
86
105
|
</p>
|
|
87
106
|
{% endif %}
|
|
88
107
|
{% endif %}
|
|
108
|
+
|
|
109
|
+
{% if params.fallbackImageUrl %}
|
|
110
|
+
{% set fallbackImageId = ["fallback-image--", params.id] | join %}
|
|
111
|
+
<noscript id="{{ fallbackImageId }}">
|
|
112
|
+
{# Note that a more detailed description of the chart is provided in the audio description above #}
|
|
113
|
+
<img
|
|
114
|
+
src="{{ params.fallbackImageUrl }}"
|
|
115
|
+
alt="{{ params.fallbackImageAlt or 'Fallback image for the chart as JavaScript is disabled' }}"
|
|
116
|
+
class="ons-chart__fallback-image"
|
|
117
|
+
/>
|
|
118
|
+
</noscript>
|
|
119
|
+
{% endif %}
|
|
89
120
|
{#
|
|
90
121
|
Footnotes for the annotations at mobile
|
|
91
122
|
Hidden from screen readers because the full text will be read out where they appear in the chart
|
|
@@ -63,6 +63,36 @@ describe('Macro: Chart', () => {
|
|
|
63
63
|
expect($('figcaption').length).toBe(0);
|
|
64
64
|
expect($('.ons-chart__download-title').length).toBe(0);
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
test('THEN: it renders the chart container with the correct aria attributes', () => {
|
|
68
|
+
expect($('.ons-chart__container').attr('aria-label')).toBe('chart container');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('GIVEN: Params: Instructions', () => {
|
|
74
|
+
describe('WHEN: instructions is provided', () => {
|
|
75
|
+
const $ = cheerio.load(
|
|
76
|
+
renderComponent('chart', {
|
|
77
|
+
...EXAMPLE_LINE_CHART_REQUIRED_PARAMS,
|
|
78
|
+
instructions: 'Some custom instructions for the chart.',
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
test('THEN: it renders the chart with the correct instructions text', () => {
|
|
83
|
+
const expectedText = 'Some custom instructions for the chart.';
|
|
84
|
+
expect($('#chart-instructions-chart-123').text().trim()).toBe(expectedText);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('WHEN: instructions is not provided', () => {
|
|
89
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_REQUIRED_PARAMS));
|
|
90
|
+
|
|
91
|
+
test('THEN: it renders the chart with the default instructions text', () => {
|
|
92
|
+
const expectedText =
|
|
93
|
+
'Use the Tab key to move focus into the chart. Once inside, use the arrow keys to navigate between data points. As you move, tooltips will be announced to describe each point. Touch device users, explore by touch or with swipe gestures.';
|
|
94
|
+
expect($('#chart-instructions-chart-123').text().trim()).toBe(expectedText);
|
|
95
|
+
});
|
|
66
96
|
});
|
|
67
97
|
});
|
|
68
98
|
|
|
@@ -193,6 +223,52 @@ describe('Macro: Chart', () => {
|
|
|
193
223
|
});
|
|
194
224
|
});
|
|
195
225
|
|
|
226
|
+
describe('GIVEN: Params: fallbackImageUrl', () => {
|
|
227
|
+
describe('WHEN: fallbackImageUrl is provided', () => {
|
|
228
|
+
const $ = cheerio.load(
|
|
229
|
+
renderComponent('chart', {
|
|
230
|
+
...EXAMPLE_LINE_CHART_WITH_CONFIG_PARAMS,
|
|
231
|
+
fallbackImageUrl: '/img/small/line-chart-screenshot.png',
|
|
232
|
+
}),
|
|
233
|
+
);
|
|
234
|
+
const noScriptFallbackImage = $(`#fallback-image--chart-456`).html();
|
|
235
|
+
test('THEN: it renders the fallback image', () => {
|
|
236
|
+
expect(noScriptFallbackImage).toContain('/img/small/line-chart-screenshot.png');
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('GIVEN: Params: fallbackImageAlt', () => {
|
|
242
|
+
describe('WHEN: fallbackImageAlt is provided', () => {
|
|
243
|
+
const $ = cheerio.load(
|
|
244
|
+
renderComponent('chart', {
|
|
245
|
+
...EXAMPLE_LINE_CHART_WITH_CONFIG_PARAMS,
|
|
246
|
+
fallbackImageUrl: '/img/small/line-chart-screenshot.png',
|
|
247
|
+
fallbackImageAlt: 'A description of the fallback image for screen readers',
|
|
248
|
+
}),
|
|
249
|
+
);
|
|
250
|
+
const noScriptFallbackImage = $(`#fallback-image--chart-456`).html();
|
|
251
|
+
test('THEN: it renders the customised fallback image alt text', () => {
|
|
252
|
+
expect(noScriptFallbackImage).toContain('alt="A description of the fallback image for screen readers"');
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe('GIVEN: Params: no fallbackImageAlt', () => {
|
|
258
|
+
describe('WHEN: fallbackImageAlt is not provided', () => {
|
|
259
|
+
const $ = cheerio.load(
|
|
260
|
+
renderComponent('chart', {
|
|
261
|
+
...EXAMPLE_LINE_CHART_WITH_CONFIG_PARAMS,
|
|
262
|
+
fallbackImageUrl: '/img/small/line-chart-screenshot.png',
|
|
263
|
+
}),
|
|
264
|
+
);
|
|
265
|
+
const noScriptFallbackImage = $(`#fallback-image--chart-456`).html();
|
|
266
|
+
test('THEN: it renders the default fallback image alt text', () => {
|
|
267
|
+
expect(noScriptFallbackImage).toContain('alt="Fallback image for the chart as JavaScript is disabled"');
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
196
272
|
describe('GIVEN: Params: Caption', () => {
|
|
197
273
|
describe('WHEN: caption is provided', () => {
|
|
198
274
|
const $ = cheerio.load(
|
|
@@ -242,7 +318,7 @@ describe('Macro: Chart', () => {
|
|
|
242
318
|
);
|
|
243
319
|
|
|
244
320
|
test('THEN: it renders the description for accessibility', () => {
|
|
245
|
-
expect($('
|
|
321
|
+
expect($('#chart-audio-description-chart-123').text()).toBe('An accessible description for screen readers.');
|
|
246
322
|
});
|
|
247
323
|
});
|
|
248
324
|
});
|
|
@@ -419,7 +495,7 @@ describe('Macro: Chart', () => {
|
|
|
419
495
|
);
|
|
420
496
|
|
|
421
497
|
test('THEN: it renders the description for accessibility', () => {
|
|
422
|
-
expect($('
|
|
498
|
+
expect($('#chart-audio-description-bar-chart-123').text()).toBe('An accessible description for screen readers.');
|
|
423
499
|
});
|
|
424
500
|
});
|
|
425
501
|
});
|
|
@@ -566,7 +642,7 @@ describe('Macro: Chart', () => {
|
|
|
566
642
|
);
|
|
567
643
|
|
|
568
644
|
test('THEN: it renders the description for accessibility', () => {
|
|
569
|
-
expect($('
|
|
645
|
+
expect($('#chart-audio-description-column-chart-123').text()).toBe('An accessible description for screen readers.');
|
|
570
646
|
});
|
|
571
647
|
});
|
|
572
648
|
});
|
|
@@ -791,7 +867,7 @@ describe('Macro: Chart', () => {
|
|
|
791
867
|
);
|
|
792
868
|
|
|
793
869
|
test('THEN: it renders the description for accessibility', () => {
|
|
794
|
-
expect($('
|
|
870
|
+
expect($('#chart-audio-description-column-chart-123').text()).toBe('An accessible description for screen readers.');
|
|
795
871
|
});
|
|
796
872
|
});
|
|
797
873
|
});
|
|
@@ -947,7 +1023,7 @@ describe('Macro: Chart', () => {
|
|
|
947
1023
|
);
|
|
948
1024
|
|
|
949
1025
|
test('THEN: it renders the description for accessibility', () => {
|
|
950
|
-
expect($('
|
|
1026
|
+
expect($('#chart-audio-description-area-chart-123').text()).toBe('An accessible description for screen readers.');
|
|
951
1027
|
});
|
|
952
1028
|
});
|
|
953
1029
|
});
|
|
@@ -1004,7 +1080,7 @@ describe('Macro: Chart', () => {
|
|
|
1004
1080
|
describe('GIVEN: Params: required', () => {
|
|
1005
1081
|
describe('WHEN: required params are provided', () => {
|
|
1006
1082
|
const $ = cheerio.load(renderComponent('chart', EXAMPLE_BOXPLOT_CHART_PARAMS));
|
|
1007
|
-
const configScript = $(`script[data-highcharts-config--
|
|
1083
|
+
const configScript = $(`script[data-highcharts-config--boxplot-chart-123]`).html();
|
|
1008
1084
|
|
|
1009
1085
|
test('THEN: it passes jest-axe checks', async () => {
|
|
1010
1086
|
const results = await axe($.html());
|
|
@@ -1020,7 +1096,7 @@ describe('Macro: Chart', () => {
|
|
|
1020
1096
|
expect(chartContainer.attr('data-highcharts-type')).toBe('boxplot');
|
|
1021
1097
|
expect(chartContainer.attr('data-highcharts-theme')).toBe('primary');
|
|
1022
1098
|
expect(chartContainer.attr('data-highcharts-title')).toBe('Example Boxplot Chart');
|
|
1023
|
-
expect(chartContainer.attr('data-highcharts-id')).toBe('
|
|
1099
|
+
expect(chartContainer.attr('data-highcharts-id')).toBe('boxplot-chart-123');
|
|
1024
1100
|
});
|
|
1025
1101
|
|
|
1026
1102
|
test('THEN: it includes the Highcharts JSON config', () => {
|
|
@@ -1124,7 +1200,7 @@ describe('Macro: Chart', () => {
|
|
|
1124
1200
|
);
|
|
1125
1201
|
|
|
1126
1202
|
test('THEN: it renders the description for accessibility', () => {
|
|
1127
|
-
expect($('
|
|
1203
|
+
expect($('#chart-audio-description-boxplot-chart-123').text()).toBe(accessibleDescription);
|
|
1128
1204
|
});
|
|
1129
1205
|
});
|
|
1130
1206
|
});
|
|
@@ -1156,7 +1232,7 @@ describe('Macro: Chart', () => {
|
|
|
1156
1232
|
describe('GIVEN: Params: Required', () => {
|
|
1157
1233
|
describe('WHEN: required params are provided', () => {
|
|
1158
1234
|
const $ = cheerio.load(renderComponent('chart', EXAMPLE_COLUMN_RANGE_CHART_PARAMS));
|
|
1159
|
-
const configScript = $(`script[data-highcharts-config--
|
|
1235
|
+
const configScript = $(`script[data-highcharts-config--column-range-chart-123]`).html();
|
|
1160
1236
|
|
|
1161
1237
|
test('THEN: it passes jest-axe accessibility checks', async () => {
|
|
1162
1238
|
const results = await axe($.html());
|
|
@@ -1170,7 +1246,7 @@ describe('Macro: Chart', () => {
|
|
|
1170
1246
|
expect(baseChart.attr('data-highcharts-title')).toBe(
|
|
1171
1247
|
'Food stores showed a strong rise on the month, while non-food stores fell',
|
|
1172
1248
|
);
|
|
1173
|
-
expect(baseChart.attr('data-highcharts-id')).toBe('
|
|
1249
|
+
expect(baseChart.attr('data-highcharts-id')).toBe('column-range-chart-123');
|
|
1174
1250
|
});
|
|
1175
1251
|
|
|
1176
1252
|
test('THEN: it includes columnrange and scatter series types', () => {
|
|
@@ -1208,7 +1284,7 @@ describe('Macro: Chart', () => {
|
|
|
1208
1284
|
});
|
|
1209
1285
|
|
|
1210
1286
|
test('THEN: it still renders the description', () => {
|
|
1211
|
-
expect($('
|
|
1287
|
+
expect($('#chart-audio-description-invalid-chart-123').text()).toBe('A detailed description');
|
|
1212
1288
|
});
|
|
1213
1289
|
|
|
1214
1290
|
test('THEN: it still renders the caption', () => {
|
|
@@ -1489,11 +1565,11 @@ describe('Macro: Chart', () => {
|
|
|
1489
1565
|
});
|
|
1490
1566
|
|
|
1491
1567
|
test('THEN: it renders the iframe', () => {
|
|
1492
|
-
expect($('
|
|
1568
|
+
expect($('.ons-chart__iframe-wrapper').length).toBe(1);
|
|
1493
1569
|
});
|
|
1494
1570
|
|
|
1495
1571
|
test('THEN: it includes the iframe title as a data attribute', () => {
|
|
1496
|
-
const iframe = $('
|
|
1572
|
+
const iframe = $('.ons-chart__iframe-wrapper');
|
|
1497
1573
|
expect(iframe.attr('data-title')).toBe(EXAMPLE_IFRAME_CHART_PARAMS.title);
|
|
1498
1574
|
});
|
|
1499
1575
|
|
|
@@ -1648,6 +1724,19 @@ describe('Macro: Chart', () => {
|
|
|
1648
1724
|
expect($('[data-invalid-chart-type]').length).toBe(0);
|
|
1649
1725
|
});
|
|
1650
1726
|
});
|
|
1727
|
+
|
|
1728
|
+
describe('WHEN: Params: fallbackImageUrl is set', () => {
|
|
1729
|
+
const $ = cheerio.load(
|
|
1730
|
+
renderComponent('chart', {
|
|
1731
|
+
...EXAMPLE_IFRAME_CHART_PARAMS,
|
|
1732
|
+
fallbackImageUrl: '/img/small/line-chart-screenshot.png',
|
|
1733
|
+
}),
|
|
1734
|
+
);
|
|
1735
|
+
const iframe = $(`.ons-chart__iframe-wrapper`);
|
|
1736
|
+
test('THEN: the iframe is hidden when JavaScript is disabled', () => {
|
|
1737
|
+
expect(iframe.attr('class')).toContain('ons-chart__non-js-hide');
|
|
1738
|
+
});
|
|
1739
|
+
});
|
|
1651
1740
|
});
|
|
1652
1741
|
});
|
|
1653
1742
|
});
|