@ons/design-system 60.0.3 → 61.0.1

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.
Files changed (47) hide show
  1. package/components/access-code/_macro.njk +6 -8
  2. package/components/accordion/_macro.njk +2 -3
  3. package/components/accordion/_macro.spec.js +9 -9
  4. package/components/accordion/accordion.dom.js +4 -4
  5. package/components/accordion/accordion.js +14 -14
  6. package/components/accordion/accordion.spec.js +6 -6
  7. package/components/collapsible/_macro.njk +20 -28
  8. package/components/collapsible/_macro.spec.js +15 -15
  9. package/components/{collapsible/_collapsible.scss → details/_details.scss} +14 -14
  10. package/components/details/_macro.njk +30 -0
  11. package/components/details/_macro.spec.js +151 -0
  12. package/components/details/details.dom.js +13 -0
  13. package/components/details/details.js +66 -0
  14. package/components/details/details.spec.js +103 -0
  15. package/components/hero/_hero.scss +2 -2
  16. package/components/modal/modal.js +12 -6
  17. package/components/modal/modal.spec.js +0 -11
  18. package/components/question/_macro.njk +4 -4
  19. package/components/question/_macro.spec.js +14 -14
  20. package/components/summary/_macro.njk +1 -1
  21. package/components/summary/_macro.spec.js +148 -1
  22. package/components/summary/_summary.scss +6 -2
  23. package/components/table/_macro.spec.js +10 -8
  24. package/components/timeout-modal/_macro.njk +19 -20
  25. package/components/timeout-modal/timeout-modal.spec.js +17 -13
  26. package/components/video/_macro.njk +18 -4
  27. package/components/video/_macro.spec.js +46 -33
  28. package/components/video/_video.scss +4 -0
  29. package/components/video/video.dom.js +13 -0
  30. package/components/video/video.js +30 -0
  31. package/components/video/video.spec.js +72 -0
  32. package/css/main.css +3 -3
  33. package/css/print.css +1 -1
  34. package/js/analytics.js +1 -5
  35. package/js/main.js +2 -1
  36. package/js/timeout.js +7 -0
  37. package/package.json +2 -1
  38. package/scripts/main.es5.js +1 -1
  39. package/scripts/main.js +1 -1
  40. package/scss/main.scss +1 -1
  41. package/scss/objects/_page.scss +1 -1
  42. package/scss/objects/_spacing.scss +1 -1
  43. package/scss/overrides/hcm.scss +1 -1
  44. package/scss/print.scss +1 -1
  45. package/components/collapsible/collapsible.dom.js +0 -13
  46. package/components/collapsible/collapsible.js +0 -66
  47. package/components/collapsible/collapsible.spec.js +0 -103
@@ -167,6 +167,7 @@ describe('script: timeout modal', () => {
167
167
  ...EXAMPLE_TIMEOUT_MODAL_BASIC,
168
168
  showModalTimeInSeconds: 1,
169
169
  sessionExpiresAt: expiryTimeInISOFormat,
170
+ enableGA: true,
170
171
  });
171
172
 
172
173
  const template = `
@@ -186,6 +187,15 @@ describe('script: timeout modal', () => {
186
187
  await page.waitForTimeout(2000);
187
188
  expect(page.url()).toContain('#!');
188
189
  });
190
+
191
+ it('and GA tracking is enabled it has the correct attributes set on the modal', async () => {
192
+ const gaLabel = await page.$eval('.ons-modal', node => node.getAttribute('data-ga-label'));
193
+ const gaAction = await page.$eval('.ons-modal', node => node.getAttribute('data-ga-action'));
194
+ const gaCategory = await page.$eval('.ons-modal', node => node.getAttribute('data-ga-category'));
195
+ expect(gaLabel).toBe('Timeout modal closed');
196
+ expect(gaAction).toBe('Modal closed by timed event');
197
+ expect(gaCategory).toBe('Timeout modal');
198
+ });
189
199
  });
190
200
  });
191
201
 
@@ -233,23 +243,17 @@ describe('script: timeout modal', () => {
233
243
  });
234
244
 
235
245
  const template = `
236
- <div class="ons-page">
237
- ${component}
238
- </div>
239
- `;
246
+ <div class="ons-page">
247
+ ${component}
248
+ </div>
249
+ `;
240
250
 
241
251
  await setTestPage('/test', template);
242
252
  });
243
253
 
244
- describe('when the page has been loaded but the modal has not been opened yet', () => {
245
- it('has the correct attributes set on the modal', async () => {
246
- const gaLabel = await page.$eval('.ons-modal', node => node.getAttribute('data-ga-label'));
247
- const gaAction = await page.$eval('.ons-modal', node => node.getAttribute('data-ga-action'));
248
- const gaCategory = await page.$eval('.ons-modal', node => node.getAttribute('data-ga-category'));
249
- expect(gaLabel).toBe('Timeout modal initialised');
250
- expect(gaAction).toBe('Modal initialised');
251
- expect(gaCategory).toBe('Timeout modal');
252
- });
254
+ it('has ga initialise attribute set', async () => {
255
+ const gaInitialise = await page.$eval('.ons-modal', node => node.getAttribute('data-ga'));
256
+ expect(gaInitialise).toBe('visible');
253
257
  });
254
258
 
255
259
  describe('when the modal is open', () => {
@@ -1,7 +1,21 @@
1
+ {% from "components/external-link/_macro.njk" import onsExternalLink %}
1
2
  {%- macro onsVideo(params) -%}
2
- <div class="ons-video">
3
- {% if params.videoEmbedUrl %}
4
- <iframe title="{{ params.title }}" class="ons-video__iframe" src="{{ params.videoEmbedUrl }}" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
5
- {% endif %}
3
+
4
+ {% set linkContents %}
5
+ {% if params.image.smallSrc %}
6
+ <img class="ons-video__img ons-u-mb-xs" {% if params.image.largeSrc %} srcset="{{ params.image.smallSrc }} 1x, {{ params.image.largeSrc }} 2x"{% endif %} src="{{ params.image.smallSrc }}" alt="{{ params.image.alt }}" loading="lazy">
7
+ {% endif %}
8
+ <span class="ons-video__link-text ons-u-mt-xs">{{ params.linkText }}</span>
9
+ {% endset %}
10
+
11
+ <div class="ons-video ons-js-video">
12
+ {{
13
+ onsExternalLink({
14
+ "url": params.videoLinkURL,
15
+ "classes": "ons-video__link ons-js-video-placeholder ons-u-db",
16
+ "linkText": linkContents
17
+ })
18
+ }}
19
+ <iframe data-src="{{ params.videoEmbedUrl }}" title="{{ params.title }}" class="ons-video__iframe ons-js-video-iframe ons-u-d-no" src="about:blank" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
6
20
  </div>
7
21
  {%- endmacro -%}
@@ -7,54 +7,67 @@ import { renderComponent } from '../../tests/helpers/rendering';
7
7
 
8
8
  const EXAMPLE_VIDEO_YOUTUBE = {
9
9
  videoEmbedUrl: 'https://www.youtube.com/embed/_EGJlvkgbPo',
10
+ videoLinkURL: 'https://www.youtube.com/watch?v=_EGJlvkgbPo',
10
11
  title: 'Census 2021 promotional TV advert',
11
- };
12
-
13
- const EXAMPLE_VIDEO_VIMEO = {
14
- videoEmbedUrl: 'https://player.vimeo.com/video/508878572',
15
- title: 'A message from National Statistician Ian Diamond for National Apprenticeship Week 2021',
12
+ linkText: 'Example link text',
13
+ image: {
14
+ smallSrc: 'example-small.png',
15
+ largeSrc: 'example-large.png',
16
+ alt: 'Example alt text',
17
+ },
16
18
  };
17
19
 
18
20
  describe('macro: video', () => {
19
- describe('mode: YouTube', () => {
20
- it('passes jest-axe checks', async () => {
21
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
21
+ it('passes jest-axe checks', async () => {
22
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
23
+
24
+ const results = await axe($.html());
25
+ expect(results).toHaveNoViolations();
26
+ });
27
+
28
+ it('outputs an `img` element with the expected `srcset`', () => {
29
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
30
+
31
+ expect($('.ons-video__img').attr('srcset')).toBe('example-small.png 1x, example-large.png 2x');
32
+ });
33
+
34
+ it('outputs an `img` element with the expected `src`', () => {
35
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
22
36
 
23
- const results = await axe($.html());
24
- expect(results).toHaveNoViolations();
25
- });
37
+ expect($('.ons-video__img').attr('src')).toBe('example-small.png');
38
+ });
26
39
 
27
- it('outputs an <iframe> element with the provided `title`', () => {
28
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
40
+ it('outputs an `img` element with the expected alt text', () => {
41
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
29
42
 
30
- expect($('iframe').attr('title')).toBe('Census 2021 promotional TV advert');
31
- });
43
+ expect($('.ons-video__img').attr('alt')).toBe('Example alt text');
44
+ });
32
45
 
33
- it('outputs an <iframe> element with the provided `videoEmbedUrl`', () => {
34
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
46
+ it('outputs the provided link text', () => {
47
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
35
48
 
36
- expect($('iframe').attr('src')).toBe('https://www.youtube.com/embed/_EGJlvkgbPo');
37
- });
49
+ expect(
50
+ $('.ons-video__link-text')
51
+ .text()
52
+ .trim(),
53
+ ).toBe('Example link text');
38
54
  });
39
55
 
40
- describe('mode: Vimeo', () => {
41
- it('passes jest-axe checks', async () => {
42
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_VIMEO));
56
+ it('outputs a hyperlink with the provided `url`', () => {
57
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
43
58
 
44
- const results = await axe($.html());
45
- expect(results).toHaveNoViolations();
46
- });
59
+ expect($('.ons-video__link').attr('href')).toBe('https://www.youtube.com/watch?v=_EGJlvkgbPo');
60
+ });
47
61
 
48
- it('outputs an <iframe> element with the provided `title`', () => {
49
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_VIMEO));
62
+ it('outputs an <iframe> element with the provided `title`', () => {
63
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
50
64
 
51
- expect($('iframe').attr('title')).toBe('A message from National Statistician Ian Diamond for National Apprenticeship Week 2021');
52
- });
65
+ expect($('iframe').attr('title')).toBe('Census 2021 promotional TV advert');
66
+ });
53
67
 
54
- it('outputs an <iframe> element with the provided `videoEmbedUrl`', () => {
55
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_VIMEO));
68
+ it('outputs an <iframe> element with the provided `videoEmbedUrl` data attribute', () => {
69
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
56
70
 
57
- expect($('iframe').attr('src')).toBe('https://player.vimeo.com/video/508878572');
58
- });
71
+ expect($('iframe').attr('data-src')).toBe('https://www.youtube.com/embed/_EGJlvkgbPo');
59
72
  });
60
73
  });
@@ -12,4 +12,8 @@
12
12
  top: 0;
13
13
  width: 100%;
14
14
  }
15
+
16
+ &__img {
17
+ width: 100%;
18
+ }
15
19
  }
@@ -0,0 +1,13 @@
1
+ import domready from '../../js/domready';
2
+
3
+ async function video() {
4
+ const videos = [...document.querySelectorAll('.ons-js-video')];
5
+
6
+ if (videos.length) {
7
+ const Video = (await import('./video')).default;
8
+
9
+ videos.forEach(component => new Video(component));
10
+ }
11
+ }
12
+
13
+ domready(video);
@@ -0,0 +1,30 @@
1
+ export default class Video {
2
+ constructor(component) {
3
+ this.component = component;
4
+ this.placeholder = component.querySelector('.ons-js-video-placeholder');
5
+ this.iframe = component.querySelector('.ons-js-video-iframe');
6
+
7
+ this.acceptCookiesButton = document.querySelector('.ons-js-accept-cookies');
8
+ if (this.acceptCookiesButton) {
9
+ this.acceptCookiesButton.addEventListener('click', this.showIframe.bind(this));
10
+ }
11
+
12
+ const allowsVideoEmbed = this.checkCookie();
13
+ if (allowsVideoEmbed) {
14
+ this.showIframe();
15
+ }
16
+ }
17
+
18
+ checkCookie() {
19
+ const campaignsCookieRegex = /^(.*)?\s*'campaigns':true\s*[^;]+(.*)?$/;
20
+ const cookieMatch = document.cookie.match(campaignsCookieRegex);
21
+ return !!cookieMatch;
22
+ }
23
+
24
+ showIframe() {
25
+ const src = this.iframe.getAttribute('data-src');
26
+ this.iframe.src = src;
27
+ this.iframe.classList.remove('ons-u-d-no');
28
+ this.placeholder.classList.add('ons-u-d-no');
29
+ }
30
+ }
@@ -0,0 +1,72 @@
1
+ import { renderComponent, setTestPage } from '../../tests/helpers/rendering';
2
+
3
+ const EXAMPLE_VIDEO_YOUTUBE = {
4
+ videoEmbedUrl: 'https://www.youtube.com/embed/_EGJlvkgbPo',
5
+ title: 'Census 2021 promotional TV advert',
6
+ linkText: 'Example link text',
7
+ };
8
+
9
+ const EXAMPLE_APPROVED_COOKIE = JSON.stringify({ campaigns: true }).replace(/"/g, "'");
10
+
11
+ describe('script: video', () => {
12
+ beforeEach(async () => {
13
+ const client = await page.target().createCDPSession();
14
+ await client.send('Network.clearBrowserCookies');
15
+ });
16
+
17
+ it('should show the placeholder content', async () => {
18
+ await setTestPage('/test', renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
19
+
20
+ const displayStyle = await page.$eval('.ons-js-video-placeholder', node => window.getComputedStyle(node).getPropertyValue('display'));
21
+ expect(displayStyle).toBe('block');
22
+ });
23
+
24
+ it('should not show the iframe', async () => {
25
+ await setTestPage('/test', renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
26
+
27
+ const displayStyle = await page.$eval('.ons-js-video-iframe', node => window.getComputedStyle(node).getPropertyValue('display'));
28
+ expect(displayStyle).toBe('none');
29
+ });
30
+
31
+ describe('when cookies are accepted on page load', () => {
32
+ beforeEach(async () => {
33
+ await page.setCookie({
34
+ name: 'ons_cookie_policy',
35
+ value: EXAMPLE_APPROVED_COOKIE,
36
+ });
37
+
38
+ await setTestPage('/test', renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
39
+ });
40
+
41
+ it('should hide the placeholder content', async () => {
42
+ const displayStyle = await page.$eval('.ons-js-video-placeholder', node => window.getComputedStyle(node).getPropertyValue('display'));
43
+ expect(displayStyle).toBe('none');
44
+ }, 10000);
45
+
46
+ it('should show the iframe', async () => {
47
+ const displayStyle = await page.$eval('.ons-js-video-iframe', node => window.getComputedStyle(node).getPropertyValue('display'));
48
+ expect(displayStyle).toBe('block');
49
+ }, 10000);
50
+ });
51
+
52
+ describe('when cookies are accepted via banner', () => {
53
+ beforeEach(async () => {
54
+ await setTestPage(
55
+ '/test',
56
+ `${renderComponent('video', EXAMPLE_VIDEO_YOUTUBE)}
57
+ <div class="ons-cookies-banner ons-u-db"><button class="ons-js-accept-cookies">Accept</button></div>`,
58
+ );
59
+ await page.click('.ons-js-accept-cookies');
60
+ });
61
+
62
+ it('should hide the placeholder content', async () => {
63
+ const displayStyle = await page.$eval('.ons-js-video-placeholder', node => window.getComputedStyle(node).getPropertyValue('display'));
64
+ expect(displayStyle).toBe('none');
65
+ });
66
+
67
+ it('should show the iframe', async () => {
68
+ const displayStyle = await page.$eval('.ons-js-video-iframe', node => window.getComputedStyle(node).getPropertyValue('display'));
69
+ expect(displayStyle).toBe('block');
70
+ });
71
+ });
72
+ });