@ons/design-system 74.0.0-next.8 → 74.0.0-widen.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/README.md +2 -2
- package/components/access-code/example-access-code-error.njk +1 -1
- package/components/access-code/example-access-code.njk +1 -1
- package/components/address-input/_macro.njk +6 -6
- package/components/address-input/_macro.spec.js +0 -3
- package/components/address-input/autosuggest.address.spec.js +23 -0
- package/components/address-output/_macro.njk +1 -1
- package/components/announcement-banner/_announcement-banner.scss +5 -0
- package/components/autosuggest/_autosuggest.scss +8 -0
- package/components/autosuggest/autosuggest.spec.js +1 -0
- package/components/autosuggest/autosuggest.ui.js +11 -5
- package/components/back-to-top/_back-to-top.scss +7 -0
- package/components/back-to-top/_macro.njk +1 -1
- package/components/back-to-top/back-to-top.js +9 -1
- package/components/back-to-top/back-to-top.spec.js +46 -0
- package/components/card/example-card-set-with-headline-figures.njk +1 -1
- package/components/char-check-limit/_macro.njk +16 -14
- package/components/chart/_macro.njk +3 -0
- package/components/chart/_macro.spec.js +49 -0
- package/components/chart/bar-chart.js +18 -12
- package/components/chart/chart.js +4 -1
- package/components/chart/common-chart-options.js +1 -0
- package/components/chart/example-stacked-column-with-line-chart.njk +64 -0
- package/components/details/_details.scss +9 -0
- package/components/details/example-details-with-warning.njk +1 -1
- package/components/details-panel/_macro.njk +1 -1
- package/components/download-resources/download-resources.spec.js +1 -4
- package/components/featured-article/_macro.njk +4 -4
- package/components/featured-article/macro.spec.js +2 -2
- package/components/feedback/_macro.njk +4 -1
- package/components/feedback/_macro.spec.js +1 -1
- package/components/figure/_figure.scss +1 -0
- package/components/figure/_macro.njk +3 -3
- package/components/footer/_macro.njk +5 -2
- package/components/header/_macro.njk +1 -1
- package/components/header/_macro.spec.js +21 -0
- package/components/hero/_hero.scss +4 -0
- package/components/input/_input.scss +4 -0
- package/components/input/_macro.njk +4 -1
- package/components/label/_label.scss +3 -0
- package/components/list/_list.scss +5 -0
- package/components/message/_message.scss +3 -3
- package/components/message-list/_message-list.scss +2 -0
- package/components/panel/_macro.njk +1 -1
- package/components/panel/_panel.scss +8 -0
- package/components/panel/example-panel-bare.njk +1 -1
- package/components/phase-banner/_phase-banner.scss +1 -0
- package/components/quote/_macro.njk +1 -1
- package/components/skip-to-content/_macro.njk +1 -1
- package/components/skip-to-content/_skip.scss +8 -0
- package/components/tabs/tabs.spec.js +1 -4
- package/css/main.css +1 -1
- package/package.json +55 -53
- package/scripts/chart.es5.js +1 -1
- package/scripts/chart.js +1 -1
- package/scripts/main.es5.js +3 -3
- package/scripts/main.js +3 -3
- package/scss/base/_typography.scss +9 -0
- package/scss/helpers/_mixins.scss +8 -0
- package/scss/objects/_container.scss +15 -3
- package/scss/utilities/_grid.scss +10 -25
- package/scss/utilities/_utilities.scss +10 -0
- package/scss/vars/_forms.scss +2 -1
- package/scss/vars/_grid.scss +20 -3
- package/scss/vars/_index.scss +1 -0
- package/scss/vars/_utilities.scss +2 -0
package/README.md
CHANGED
|
@@ -147,9 +147,9 @@ Checkout the branch locally and run:
|
|
|
147
147
|
|
|
148
148
|
### Handling VR test failures
|
|
149
149
|
|
|
150
|
-
If the VR tests fail locally, you
|
|
150
|
+
If the VR tests fail locally, you'll see an error starting with `Error: docker run --rm -i --add-host=host.docker.internal:host-gateway...`
|
|
151
151
|
|
|
152
|
-
`npx http-server backstop_data
|
|
152
|
+
`npx http-server backstop_data -p 8008 -o /html_report/` - View the report in your browser.
|
|
153
153
|
|
|
154
154
|
### Approving VR test reference image changes
|
|
155
155
|
|
|
@@ -76,7 +76,7 @@ layout: ~
|
|
|
76
76
|
"variant": "warn"
|
|
77
77
|
})
|
|
78
78
|
%}
|
|
79
|
-
Someone in your household must still complete a study using this household access code
|
|
79
|
+
<p>Someone in your household must still complete a study using this household access code</p>
|
|
80
80
|
{% endcall %}
|
|
81
81
|
{% endset %}
|
|
82
82
|
|
|
@@ -53,7 +53,7 @@ layout: ~
|
|
|
53
53
|
"variant": "warn"
|
|
54
54
|
})
|
|
55
55
|
%}
|
|
56
|
-
Someone in your household must still complete a study using this household access code
|
|
56
|
+
<p>Someone in your household must still complete a study using this household access code</p>
|
|
57
57
|
{% endcall %}
|
|
58
58
|
{% endset %}
|
|
59
59
|
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"text": params.organisation.label
|
|
20
20
|
},
|
|
21
21
|
"classes": "ons-js-address-organisation",
|
|
22
|
-
"width": "20@m",
|
|
23
22
|
"name": params.id + "-organisation",
|
|
24
23
|
"error": params.organisation.error
|
|
25
24
|
})
|
|
@@ -34,7 +33,6 @@
|
|
|
34
33
|
"text": params.line1.label
|
|
35
34
|
},
|
|
36
35
|
"classes": "ons-js-address-line1",
|
|
37
|
-
"width": "20@m",
|
|
38
36
|
"name": params.id + "-line1",
|
|
39
37
|
"error": params.line1.error
|
|
40
38
|
})
|
|
@@ -49,7 +47,6 @@
|
|
|
49
47
|
"text": params.line2.label
|
|
50
48
|
},
|
|
51
49
|
"classes": "ons-js-address-line2",
|
|
52
|
-
"width": "20@m",
|
|
53
50
|
"name": params.id + "-line2",
|
|
54
51
|
"error": params.line2.error
|
|
55
52
|
})
|
|
@@ -165,9 +162,12 @@
|
|
|
165
162
|
})
|
|
166
163
|
}}
|
|
167
164
|
{% if params.manualLinkText %}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
165
|
+
{# p tag ensures reading width is applied #}
|
|
166
|
+
<p class="ons-u-mb-no">
|
|
167
|
+
<a href="{{ params.manualLinkUrl }}" class="ons-js-address-manual-btn ons-u-mt-s ons-u-dib"
|
|
168
|
+
>{{ params.manualLinkText }}</a
|
|
169
|
+
>
|
|
170
|
+
</p>
|
|
171
171
|
{% endif %}
|
|
172
172
|
</div>
|
|
173
173
|
{% endif %}
|
|
@@ -176,7 +176,6 @@ describe('FOR: Macro: Address-input', () => {
|
|
|
176
176
|
text: 'Organisation name',
|
|
177
177
|
},
|
|
178
178
|
value: 'Example Organisation',
|
|
179
|
-
width: '20@m',
|
|
180
179
|
error: { text: 'Server error: organisation name' },
|
|
181
180
|
});
|
|
182
181
|
});
|
|
@@ -191,7 +190,6 @@ describe('FOR: Macro: Address-input', () => {
|
|
|
191
190
|
text: 'Address line 1',
|
|
192
191
|
},
|
|
193
192
|
value: 'Flat 12345',
|
|
194
|
-
width: '20@m',
|
|
195
193
|
error: { text: 'Server error: address line 1' },
|
|
196
194
|
});
|
|
197
195
|
});
|
|
@@ -207,7 +205,6 @@ describe('FOR: Macro: Address-input', () => {
|
|
|
207
205
|
text: 'Address line 2',
|
|
208
206
|
},
|
|
209
207
|
value: '12345 The Road',
|
|
210
|
-
width: '20@m',
|
|
211
208
|
error: { text: 'Server error: address line 2' },
|
|
212
209
|
});
|
|
213
210
|
});
|
|
@@ -411,6 +411,29 @@ describe('script: address-input', () => {
|
|
|
411
411
|
});
|
|
412
412
|
});
|
|
413
413
|
});
|
|
414
|
+
|
|
415
|
+
describe('when a grouped suggestion is selected with the mouse', () => {
|
|
416
|
+
beforeEach(async () => {
|
|
417
|
+
const options = await page.$$('.ons-autosuggest__option');
|
|
418
|
+
await options[0].click();
|
|
419
|
+
await setTimeout(400);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('makes expected bucket request', async () => {
|
|
423
|
+
expect(
|
|
424
|
+
await apiFaker.getRequestCount(
|
|
425
|
+
'/addresses/eq/bucket?postcode=CF14%202AA&streetname=Penlline%20Road&townname=Whitchurch&groupfullpostcodes=combo',
|
|
426
|
+
),
|
|
427
|
+
).toBe(1);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('keeps nested suggestion entries after blur timeout', async () => {
|
|
431
|
+
const suggestions = await page.$$eval('.ons-autosuggest__option', (nodes) =>
|
|
432
|
+
nodes.map((node) => node.textContent.trim()),
|
|
433
|
+
);
|
|
434
|
+
expect(suggestions).toEqual(['197 College Road, Whitchurch, Cardiff, CF14 2AB']);
|
|
435
|
+
});
|
|
436
|
+
});
|
|
414
437
|
});
|
|
415
438
|
|
|
416
439
|
describe('when there is an error retrieving the address', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{% macro onsAddressOutput(params) %}
|
|
2
|
-
<div class="ons-address-output{{ ' ' + params.classes if params.classes else '' }}">
|
|
2
|
+
<div class="ons-address-output ons-u-reading-width{{ ' ' + params.classes if params.classes else '' }}">
|
|
3
3
|
<p class="ons-address-output__lines">
|
|
4
4
|
{% if params.unit %}
|
|
5
5
|
<span class="ons-address-output__unit">{{ params.unit }}</span><br />
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
&__results-title {
|
|
29
|
+
@include reading-width;
|
|
30
|
+
|
|
29
31
|
background: var(--ons-color-grey-15);
|
|
30
32
|
border-bottom: 1px solid var(--ons-color-input-border);
|
|
31
33
|
padding: 0.25rem 0.5rem;
|
|
@@ -41,6 +43,12 @@
|
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
&__option-text {
|
|
47
|
+
@include reading-width;
|
|
48
|
+
|
|
49
|
+
display: block;
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
&__option {
|
|
45
53
|
cursor: pointer;
|
|
46
54
|
margin: 0;
|
|
@@ -657,6 +657,7 @@ describe('script: autosuggest', () => {
|
|
|
657
657
|
);
|
|
658
658
|
|
|
659
659
|
await page.type('.ons-js-autosuggest-input', 'England', { delay: 20 });
|
|
660
|
+
await page.waitForSelector('.ons-autosuggest__option');
|
|
660
661
|
await page.keyboard.press('ArrowUp');
|
|
661
662
|
await page.keyboard.press('Enter');
|
|
662
663
|
// Unfocus the autosuggest input
|
|
@@ -201,6 +201,8 @@ export default class AutosuggestUI {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
handleFocus() {
|
|
204
|
+
this.blurring = false;
|
|
205
|
+
|
|
204
206
|
if (this.allowMultiple === 'true' && this.allSelections.length && this.input.value.slice(-1) !== ' ' && this.input.value !== '') {
|
|
205
207
|
this.input.value = `${this.input.value}, `;
|
|
206
208
|
}
|
|
@@ -382,7 +384,7 @@ export default class AutosuggestUI {
|
|
|
382
384
|
innerHTML +
|
|
383
385
|
`<span class="ons-autosuggest__category ons-u-lighter ons-u-fs-s ons-u-db">${resultItem.category}</span>`;
|
|
384
386
|
}
|
|
385
|
-
listElement.innerHTML = innerHTML
|
|
387
|
+
listElement.innerHTML = `<span class="ons-autosuggest__option-text">${innerHTML}</span>`;
|
|
386
388
|
listElement.addEventListener('click', () => {
|
|
387
389
|
this.selectResult(index);
|
|
388
390
|
});
|
|
@@ -399,7 +401,7 @@ export default class AutosuggestUI {
|
|
|
399
401
|
const listElement = document.createElement('li');
|
|
400
402
|
listElement.className = `${classAutosuggestOption} ${classAutosuggestOptionMoreResults}`;
|
|
401
403
|
listElement.setAttribute('aria-hidden', 'true');
|
|
402
|
-
listElement.innerHTML = DOMPurify.sanitize(this.moreResults)
|
|
404
|
+
listElement.innerHTML = `<span class="ons-autosuggest__option-text">${DOMPurify.sanitize(this.moreResults)}</span>`;
|
|
403
405
|
this.listbox.appendChild(listElement);
|
|
404
406
|
}
|
|
405
407
|
|
|
@@ -438,11 +440,14 @@ export default class AutosuggestUI {
|
|
|
438
440
|
message = this.typeMore;
|
|
439
441
|
this.setAriaStatus(message);
|
|
440
442
|
this.listbox.innerHTML = DOMPurify.sanitize(
|
|
441
|
-
`<li class="${classAutosuggestOption} ${classAutosuggestOptionNoResults}">${message}</li>`,
|
|
443
|
+
`<li class="${classAutosuggestOption} ${classAutosuggestOptionNoResults}"><span class="ons-autosuggest__option-text">${message}</span></li>`,
|
|
442
444
|
);
|
|
443
445
|
} else if (status > 400 || status === '') {
|
|
444
446
|
const sanitizedHref = DOMPurify.sanitize(window.location.href);
|
|
445
|
-
message =
|
|
447
|
+
message =
|
|
448
|
+
'<p>' +
|
|
449
|
+
this.errorAPI +
|
|
450
|
+
(this.errorAPILinkText ? ' <a href="' + sanitizedHref + '">' + this.errorAPILinkText + '</a>.</p>' : '');
|
|
446
451
|
let ariaMessage = this.errorAPI + (this.errorAPILinkText ? ' ' + this.errorAPILinkText : '');
|
|
447
452
|
|
|
448
453
|
this.input.setAttribute('disabled', true);
|
|
@@ -457,7 +462,7 @@ export default class AutosuggestUI {
|
|
|
457
462
|
} else {
|
|
458
463
|
message = this.noResults;
|
|
459
464
|
this.listbox.innerHTML = DOMPurify.sanitize(
|
|
460
|
-
`<li class="${classAutosuggestOption} ${classAutosuggestOptionNoResults}">${message}</li>`,
|
|
465
|
+
`<li class="${classAutosuggestOption} ${classAutosuggestOptionNoResults}"><span class="ons-autosuggest__option-text">${message}</span></li>`,
|
|
461
466
|
);
|
|
462
467
|
}
|
|
463
468
|
}
|
|
@@ -513,6 +518,7 @@ export default class AutosuggestUI {
|
|
|
513
518
|
|
|
514
519
|
selectResult(index) {
|
|
515
520
|
if (this.results.length) {
|
|
521
|
+
clearTimeout(this.blurTimeout);
|
|
516
522
|
this.settingResult = true;
|
|
517
523
|
const result = this.results[index || this.highlightedResultIndex || 0];
|
|
518
524
|
const resultItem = result.item ?? result;
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
margin-left: 0.25rem;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
// This element also gets a margin-left value set in the JS to match the content left spacing
|
|
7
|
+
&__content {
|
|
8
|
+
@include reading-width;
|
|
9
|
+
|
|
10
|
+
display: inline-block;
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
&__enabled {
|
|
7
14
|
background: none;
|
|
8
15
|
width: fit-content;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
{% macro onsBackToTop(params) %}
|
|
4
4
|
<div class="ons-back-to-top ons-js-back-to-top ons-back-to-top__enabled">
|
|
5
5
|
<a href="#{{ params.anchor | default('top') }}" class="ons-back-to-top__link">
|
|
6
|
-
<span>
|
|
6
|
+
<span class="ons-back-to-top__content">
|
|
7
7
|
{{-
|
|
8
8
|
onsIcon({
|
|
9
9
|
"iconType": 'arrow-up',
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export default class BackToTop {
|
|
2
2
|
constructor(component) {
|
|
3
3
|
this.component = component;
|
|
4
|
-
|
|
4
|
+
let el = this.component;
|
|
5
|
+
while (el && !el.previousElementSibling) {
|
|
6
|
+
el = el.parentElement;
|
|
7
|
+
}
|
|
8
|
+
this.content = el ? el.previousElementSibling : null;
|
|
5
9
|
this.target = document.getElementById(this.component.firstElementChild.href.split('#')[1]);
|
|
6
10
|
this.contentleft;
|
|
7
11
|
this.updateContentDetails();
|
|
@@ -27,6 +31,10 @@ export default class BackToTop {
|
|
|
27
31
|
scrollPosition = -this.target.getBoundingClientRect().top + window.innerHeight;
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
// In the extremely unlikely situation where there is no content at all above the back to top component, exit early
|
|
35
|
+
if (!this.content) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
30
38
|
const contentRect = this.content.getBoundingClientRect();
|
|
31
39
|
const windowHeight = window.innerHeight;
|
|
32
40
|
const contentBottom = contentRect.bottom;
|
|
@@ -117,3 +117,49 @@ describe('script: back-to-top', () => {
|
|
|
117
117
|
expect(previousWidth).not.toEqual(newWidth);
|
|
118
118
|
});
|
|
119
119
|
});
|
|
120
|
+
|
|
121
|
+
describe('script: back-to-top without an adjacent previous sibling', () => {
|
|
122
|
+
it('does not throw errors when the component is nested several levels deep with no immediate previous sibling', async () => {
|
|
123
|
+
const pageErrors = [];
|
|
124
|
+
const handler = (err) => pageErrors.push(err.message);
|
|
125
|
+
page.on('pageerror', handler);
|
|
126
|
+
|
|
127
|
+
await setTestPage(
|
|
128
|
+
'/test',
|
|
129
|
+
`
|
|
130
|
+
<div>
|
|
131
|
+
<p>Content above</p>
|
|
132
|
+
</div>
|
|
133
|
+
<div>
|
|
134
|
+
<div>
|
|
135
|
+
<div>
|
|
136
|
+
${renderComponent('back-to-top', {})}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
`,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
await page.evaluate(() => {
|
|
144
|
+
window.scrollTo(0, window.innerHeight * 2 + 10);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
page.off('pageerror', handler);
|
|
148
|
+
expect(pageErrors).toHaveLength(0);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('does not throw errors when there is no content preceding the back-to-top component', async () => {
|
|
152
|
+
const pageErrors = [];
|
|
153
|
+
const handler = (err) => pageErrors.push(err.message);
|
|
154
|
+
page.on('pageerror', handler);
|
|
155
|
+
|
|
156
|
+
await setTestPage('/test', `${renderComponent('back-to-top', {})}`);
|
|
157
|
+
|
|
158
|
+
await page.evaluate(() => {
|
|
159
|
+
window.scrollTo(0, window.innerHeight * 2 + 10);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
page.off('pageerror', handler);
|
|
163
|
+
expect(pageErrors).toHaveLength(0);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{% from "components/card/_macro.njk" import onsCard %}
|
|
2
2
|
|
|
3
3
|
<div class="ons-container">
|
|
4
|
-
<div class="ons-grid ons-grid-flex-gap ons-grid-flex
|
|
4
|
+
<div class="ons-grid ons-grid-flex-gap ons-grid-flex--vertical-top">
|
|
5
5
|
<div class="ons-grid__col ons-grid__col--flex-col ons-grid__col--stretch">
|
|
6
6
|
{{
|
|
7
7
|
onsCard({
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{% macro onsCharLimit(params) %}
|
|
2
|
-
|
|
3
|
-
{%
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
<div class="ons-u-reading-width">
|
|
3
|
+
{% if params.variant == "check" %}
|
|
4
|
+
{% set content = caller() %}
|
|
5
|
+
<span class="ons-js-char-check-input">{{ content | safe }}</span>
|
|
6
|
+
{% endif %}
|
|
7
|
+
<span
|
|
8
|
+
id="{{ params.id }}"
|
|
9
|
+
class="ons-input__limit ons-u-fs-s--b ons-u-d-no ons-u-mt-2xs"
|
|
10
|
+
data-count-type="{{ params.variant if params.variant == 'word' else 'char' }}"
|
|
11
|
+
data-message-singular="{% if params.variant == 'word' %}{{ params.wordCountSingular }}{% else %}{{ params.charCountSingular }}{% endif %}"
|
|
12
|
+
data-message-plural="{% if params.variant == 'word' %}{{ params.wordCountPlural }}{% else %}{{ params.charCountPlural }}{% endif %}"
|
|
13
|
+
data-message-over-limit-singular="{% if params.variant == 'word' %}{{ params.wordCountOverLimitSingular | default("You have exceeded the word limit by {x} word") }}{% else %}{{ params.charCountOverLimitSingular | default("You have exceeded the character limit by {x} character") }}{% endif %}"
|
|
14
|
+
data-message-over-limit-plural="{% if params.variant == 'word' %}{{ params.wordCountOverLimitPlural | default("You have exceeded the word limit by {x} words") }}{% else %}{{ params.charCountOverLimitPlural | default("You have exceeded the character limit by {x} characters") }}{% endif %}"
|
|
15
|
+
>
|
|
16
|
+
</span>
|
|
17
|
+
</div>
|
|
16
18
|
{% endmacro %}
|
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
{% if params.yAxis.customReferenceLineValue %}
|
|
43
43
|
data-highcharts-custom-reference-line-value="{{ params.yAxis.customReferenceLineValue }}"
|
|
44
44
|
{% endif %}
|
|
45
|
+
{% if params.dataLabelDecimalPoints and params.dataLabelDecimalPoints >= 1 and params.dataLabelDecimalPoints <= 2 %}
|
|
46
|
+
data-highcharts-data-label-decimal-points="{{ params.dataLabelDecimalPoints }}"
|
|
47
|
+
{% endif %}
|
|
45
48
|
{% endif %}
|
|
46
49
|
>
|
|
47
50
|
{%
|
|
@@ -885,6 +885,55 @@ describe('Macro: Chart', () => {
|
|
|
885
885
|
});
|
|
886
886
|
});
|
|
887
887
|
|
|
888
|
+
describe('GIVEN: Params: dataLabelDecimalPoints', () => {
|
|
889
|
+
describe('WHEN: dataLabelDecimalPoints is provided', () => {
|
|
890
|
+
const $ = cheerio.load(
|
|
891
|
+
renderComponent('chart', {
|
|
892
|
+
...EXAMPLE_BAR_CHART_PARAMS,
|
|
893
|
+
dataLabelDecimalPoints: 2,
|
|
894
|
+
}),
|
|
895
|
+
);
|
|
896
|
+
|
|
897
|
+
test('THEN: it includes the data label decimal points data attribute', () => {
|
|
898
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-data-label-decimal-points')).toBe('2');
|
|
899
|
+
});
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
describe('WHEN: dataLabelDecimalPoints is not provided', () => {
|
|
903
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_BAR_CHART_PARAMS));
|
|
904
|
+
|
|
905
|
+
test('THEN: it does not include the data label decimal points data attribute', () => {
|
|
906
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-data-label-decimal-points')).toBe(undefined);
|
|
907
|
+
});
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
describe('WHEN: dataLabelDecimalPoints is greater than 2', () => {
|
|
911
|
+
const $ = cheerio.load(
|
|
912
|
+
renderComponent('chart', {
|
|
913
|
+
...EXAMPLE_BAR_CHART_PARAMS,
|
|
914
|
+
dataLabelDecimalPoints: 3,
|
|
915
|
+
}),
|
|
916
|
+
);
|
|
917
|
+
|
|
918
|
+
test('THEN: it does not include the data label decimal points data attribute', () => {
|
|
919
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-data-label-decimal-points')).toBe(undefined);
|
|
920
|
+
});
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
describe('WHEN: dataLabelDecimalPoints is less than 1', () => {
|
|
924
|
+
const $ = cheerio.load(
|
|
925
|
+
renderComponent('chart', {
|
|
926
|
+
...EXAMPLE_BAR_CHART_PARAMS,
|
|
927
|
+
dataLabelDecimalPoints: 0,
|
|
928
|
+
}),
|
|
929
|
+
);
|
|
930
|
+
|
|
931
|
+
test('THEN: it does not include the data label decimal points data attribute', () => {
|
|
932
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-data-label-decimal-points')).toBe(undefined);
|
|
933
|
+
});
|
|
934
|
+
});
|
|
935
|
+
});
|
|
936
|
+
|
|
888
937
|
describe('GIVEN: Params: caption', () => {
|
|
889
938
|
describe('WHEN: caption is provided', () => {
|
|
890
939
|
const $ = cheerio.load(
|
|
@@ -5,7 +5,23 @@ class BarChart {
|
|
|
5
5
|
this.constants = ChartConstants.constants();
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
getBarChartOptions = (useStackedLayout) => {
|
|
8
|
+
getBarChartOptions = (useStackedLayout, dataLabelDecimalPoints) => {
|
|
9
|
+
const dataLabels = {
|
|
10
|
+
enabled: true,
|
|
11
|
+
inside: false,
|
|
12
|
+
style: {
|
|
13
|
+
textOutline: 'none',
|
|
14
|
+
// The design system does not include a semibold font weight, so we use 700 (bold) as an alternative.
|
|
15
|
+
fontWeight: '700',
|
|
16
|
+
color: this.constants.labelColor,
|
|
17
|
+
fontSize: this.constants.defaultFontSize,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
if (dataLabelDecimalPoints !== undefined) {
|
|
21
|
+
dataLabels.formatter = function () {
|
|
22
|
+
return Number(this.y).toFixed(dataLabelDecimalPoints);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
9
25
|
return {
|
|
10
26
|
plotOptions: {
|
|
11
27
|
bar: {
|
|
@@ -18,17 +34,7 @@ class BarChart {
|
|
|
18
34
|
borderRadius: 0,
|
|
19
35
|
// Set the data labels to be enabled and positioned outside the bars
|
|
20
36
|
// We can add custom formatting on each chart to move the labels inside the bars if the bar is wide enough
|
|
21
|
-
dataLabels
|
|
22
|
-
enabled: true,
|
|
23
|
-
inside: false,
|
|
24
|
-
style: {
|
|
25
|
-
textOutline: 'none',
|
|
26
|
-
// The design system does not include a semibold font weight, so we use 700 (bold) as an alternative.
|
|
27
|
-
fontWeight: '700',
|
|
28
|
-
color: this.constants.labelColor,
|
|
29
|
-
fontSize: this.constants.defaultFontSize,
|
|
30
|
-
},
|
|
31
|
-
},
|
|
37
|
+
dataLabels,
|
|
32
38
|
},
|
|
33
39
|
series: {
|
|
34
40
|
stacking: useStackedLayout ? 'normal' : null,
|
|
@@ -73,6 +73,9 @@ class HighchartsBaseChart {
|
|
|
73
73
|
this.customReferenceLineValue = this.node.dataset.highchartsCustomReferenceLineValue
|
|
74
74
|
? parseFloat(this.node.dataset.highchartsCustomReferenceLineValue)
|
|
75
75
|
: undefined;
|
|
76
|
+
this.dataLabelDecimalPoints = this.node.dataset.highchartsDataLabelDecimalPoints
|
|
77
|
+
? parseInt(this.node.dataset.highchartsDataLabelDecimalPoints, 10)
|
|
78
|
+
: undefined;
|
|
76
79
|
this.specificChartOptions = new SpecificChartOptions(
|
|
77
80
|
this.theme,
|
|
78
81
|
this.chartType,
|
|
@@ -153,7 +156,7 @@ class HighchartsBaseChart {
|
|
|
153
156
|
setSpecificChartOptions = () => {
|
|
154
157
|
const specificChartOptions = this.specificChartOptions.getOptions();
|
|
155
158
|
const lineChartOptions = this.lineChart.getLineChartOptions();
|
|
156
|
-
const barChartOptions = this.barChart.getBarChartOptions(this.useStackedLayout);
|
|
159
|
+
const barChartOptions = this.barChart.getBarChartOptions(this.useStackedLayout, this.dataLabelDecimalPoints);
|
|
157
160
|
const columnRangeChartOptions = this.columnRangeChart.getColumnRangeChartOptions();
|
|
158
161
|
const columnChartOptions = this.columnChart.getColumnChartOptions(this.config, this.useStackedLayout, this.extraLines);
|
|
159
162
|
const areaChartOptions = this.areaChart.getAreaChartOptions();
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{% from "components/chart/_macro.njk" import onsChart %}
|
|
2
|
+
{{
|
|
3
|
+
onsChart({
|
|
4
|
+
"chartType": "column",
|
|
5
|
+
"description": "Monthly percentage change in retail sales volume by store type, Great Britain, January to June 2025",
|
|
6
|
+
"theme": "primary",
|
|
7
|
+
"title": "Food stores showed a strong rise on the month, while non-food stores fell",
|
|
8
|
+
"subtitle": "Figure 6: Upward contribution to monthly percentage change in total retail sales",
|
|
9
|
+
"id": "uuid",
|
|
10
|
+
"useStackedLayout": true,
|
|
11
|
+
"caption": "Source: Monthly Business Survey, Retail Sales Inquiry from the Office for National Statistics",
|
|
12
|
+
"download": {
|
|
13
|
+
"title": "Download Figure 6 data",
|
|
14
|
+
"itemsList": [
|
|
15
|
+
{ "text": "Excel spreadsheet (XLSX format, 22KB)", "url": "#",
|
|
16
|
+
"download": "file" },
|
|
17
|
+
{ "text": "Simple text file (CSV format, 28KB)", "url": "#",
|
|
18
|
+
"download": "file" },
|
|
19
|
+
{ "text": "Image (PNG format, 32KB)", "url": "#",
|
|
20
|
+
"download": "file" }
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"legend": true,
|
|
24
|
+
"series": [
|
|
25
|
+
{
|
|
26
|
+
"name": "Food stores",
|
|
27
|
+
"data": [1.5, 0.8, 1.2, 0.9, 1.1, 1.4]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "Non-food stores",
|
|
31
|
+
"data": [0.5, -0.2, 0.6, 0.8, 0.3, 0.4]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "Non-store retailing",
|
|
35
|
+
"data": [0.2, 0.1, 0.3, 0.2, 0.4, 0.3]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "Automotive fuel",
|
|
39
|
+
"data": [0.3, 0.2, -0.1, 0.4, 0.2, 0.5]
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "Another test data source",
|
|
43
|
+
"data": [1.5, 0.8, 1.5, 0.2, 0.8, 1.3],
|
|
44
|
+
"type": "line"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"xAxis": {
|
|
48
|
+
"categories": [
|
|
49
|
+
"Jan 2025",
|
|
50
|
+
"Feb 2025",
|
|
51
|
+
"Mar 2025",
|
|
52
|
+
"Apr 2025",
|
|
53
|
+
"May 2025",
|
|
54
|
+
"Jun 2025"
|
|
55
|
+
],
|
|
56
|
+
"title": "Month"
|
|
57
|
+
},
|
|
58
|
+
"yAxis": {
|
|
59
|
+
"title": "Monthly percentage change (%)"
|
|
60
|
+
},
|
|
61
|
+
"percentageHeightDesktop": 40,
|
|
62
|
+
"percentageHeightMobile": 90
|
|
63
|
+
})
|
|
64
|
+
}}
|
|
@@ -77,6 +77,15 @@ $details-caret-width: 1.75rem;
|
|
|
77
77
|
display: block;
|
|
78
78
|
margin: 1rem 0 0 0.5rem;
|
|
79
79
|
padding: 0 0 0 1.5rem;
|
|
80
|
+
|
|
81
|
+
// Restrict the width of textual content within the details content (paragraphs are already globally restricted)
|
|
82
|
+
|
|
83
|
+
ul,
|
|
84
|
+
ol,
|
|
85
|
+
label,
|
|
86
|
+
legend {
|
|
87
|
+
@include reading-width;
|
|
88
|
+
}
|
|
80
89
|
}
|
|
81
90
|
}
|
|
82
91
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
})
|
|
22
22
|
}}
|
|
23
23
|
</span>
|
|
24
|
-
<span class="ons-details-panel__banner-detail-title">
|
|
24
|
+
<span class="ons-details-panel__banner-detail-title ons-u-reading-width">
|
|
25
25
|
<span class="ons-details-panel__banner-detail-title--open"> {{ openText }} </span>
|
|
26
26
|
<span class="ons-details-panel__banner-detail-title--close"> {{ closeText }} </span>
|
|
27
27
|
</span>
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { setViewport } from '../../tests/helpers/puppeteer';
|
|
1
|
+
import { iPhoneX, setViewport } from '../../tests/helpers/puppeteer';
|
|
3
2
|
import { renderComponent, renderTemplate, setTestPage } from '../../tests/helpers/rendering';
|
|
4
3
|
|
|
5
|
-
const iPhoneX = KnownDevices['iPhone X'];
|
|
6
|
-
|
|
7
4
|
/* eslint-disable indent */
|
|
8
5
|
const EXAMPLE_PAGE = `
|
|
9
6
|
<div class="ons-page">
|