@ons/design-system 66.0.2 → 67.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 (46) hide show
  1. package/README.md +3 -2
  2. package/components/accordion/_macro.spec.js +2 -8
  3. package/components/accordion/accordion.dom.js +2 -2
  4. package/components/accordion/accordion.spec.js +22 -19
  5. package/components/accordion/example-accordion-open.njk +3 -3
  6. package/components/card/_card.scss +1 -1
  7. package/components/checkboxes/_macro.njk +1 -1
  8. package/components/checkboxes/example-checkboxes-with-revealed-checkboxes-expanded.njk +1 -1
  9. package/components/checkboxes/example-checkboxes-with-revealed-checkboxes.njk +1 -1
  10. package/components/cookies-banner/_macro.njk +1 -1
  11. package/components/cookies-banner/_macro.spec.js +1 -1
  12. package/components/details/_details.scss +66 -57
  13. package/components/details/_macro.njk +5 -5
  14. package/components/details/_macro.spec.js +3 -10
  15. package/components/details/details.dom.js +1 -1
  16. package/components/details/details.js +13 -1
  17. package/components/details/details.spec.js +43 -11
  18. package/components/details/example-details-with-warning.njk +1 -2
  19. package/components/footer/_macro.njk +1 -1
  20. package/components/header/_header.scss +4 -0
  21. package/components/header/_macro.njk +17 -17
  22. package/components/header/_macro.spec.js +128 -5
  23. package/components/header/example-header-external-with-navigation-and-search.njk +57 -0
  24. package/components/input/_input-type.scss +2 -2
  25. package/components/input/_macro.njk +1 -1
  26. package/components/input/_macro.spec.js +4 -16
  27. package/components/input/input.dom.js +11 -0
  28. package/components/input/input.js +14 -0
  29. package/components/input/input.spec.js +28 -0
  30. package/components/label/_macro.njk +2 -2
  31. package/components/navigation/_macro.njk +3 -1
  32. package/components/related-content/_macro.njk +28 -30
  33. package/components/section-navigation/_macro.njk +68 -55
  34. package/components/section-navigation/_section-navigation.scss +20 -2
  35. package/components/video/_macro.njk +11 -11
  36. package/css/main.css +1 -1
  37. package/css/print.css +1 -1
  38. package/js/main.js +1 -0
  39. package/layout/_template.njk +29 -30
  40. package/package.json +1 -1
  41. package/scripts/main.es5.js +1 -1
  42. package/scripts/main.js +1 -1
  43. package/scss/objects/_page.scss +3 -5
  44. package/scss/print.scss +28 -5
  45. package/components/collapsible/_macro.njk +0 -22
  46. package/components/collapsible/_macro.spec.js +0 -151
package/README.md CHANGED
@@ -130,11 +130,12 @@ Checkout the branch locally and run:
130
130
 
131
131
  `yarn test-visual:approve` - This will approve the failures/diff caught by the tests.
132
132
 
133
- `yarn test-visual:reference` - This will update the reference images locally on your machine.
134
133
 
135
134
  `git lfs push --all origin` - First commit the files in the normal way then run the command. This will push the new reference images to Git LFS.
136
135
 
137
- You can then commit and push your changes. The test images that would have been created when you ran `yest test-visual` are gitignored and the new references images will be pushed to Git LFS.
136
+ You can then commit and push the updated references and your changes to your branch. The test images that would have been created when you ran `yarn test-visual` are gitignored and the new references images will be pushed to Git LFS.
137
+
138
+ If your local tests are failing but you have approved them, run `yarn test-visual:reference`. This will update the reference images locally on your machine.
138
139
 
139
140
  ## Build
140
141
 
@@ -57,10 +57,7 @@ describe('macro: accordion', () => {
57
57
  it('has provided title text', () => {
58
58
  const $ = cheerio.load(renderComponent('accordion', EXAMPLE_ACCORDION_WITH_TWO_ITEMS));
59
59
 
60
- const titleText = $('.ons-details__title')
61
- .first()
62
- .text()
63
- .trim();
60
+ const titleText = $('.ons-details__title').first().text().trim();
64
61
  expect(titleText).toBe('Title for item 1');
65
62
  });
66
63
 
@@ -84,10 +81,7 @@ describe('macro: accordion', () => {
84
81
  it('has provided content text', () => {
85
82
  const $ = cheerio.load(renderComponent('accordion', EXAMPLE_ACCORDION_WITH_TWO_ITEMS));
86
83
 
87
- const titleText = $('.ons-details__content')
88
- .first()
89
- .text()
90
- .trim();
84
+ const titleText = $('.ons-details__content').first().text().trim();
91
85
  expect(titleText).toBe('Content for item 1');
92
86
  });
93
87
 
@@ -8,9 +8,9 @@ async function initialiseAccordions() {
8
8
 
9
9
  const Details = (await import('../details/details')).default;
10
10
  const Accordion = (await import('./accordion')).default;
11
- const detailsEls = detailsComponents.map(element => new Details(element));
11
+ const detailsEls = detailsComponents.map((element) => new Details(element));
12
12
 
13
- toggleAllButtons.forEach(button => {
13
+ toggleAllButtons.forEach((button) => {
14
14
  new Accordion(button, detailsEls);
15
15
  });
16
16
  }
@@ -39,10 +39,11 @@ describe('script: accordion', () => {
39
39
  }),
40
40
  );
41
41
 
42
- const openElements = await page.$$eval('.ons-js-details', nodes => nodes.filter(node => node.open));
43
- expect(openElements[0]).not.toBe(undefined);
44
- expect(openElements[1]).not.toBe(undefined);
45
- expect(openElements[2]).not.toBe(undefined);
42
+ const detailsElementStates = await page.$$eval('.ons-js-details', (nodes) =>
43
+ nodes.map((node) => node.classList.contains('ons-details--open')),
44
+ );
45
+
46
+ expect(detailsElementStates).toEqual([true, true, true]);
46
47
  });
47
48
 
48
49
  it('sets toggle all button label to "Hide all" when open is specified', async () => {
@@ -54,7 +55,7 @@ describe('script: accordion', () => {
54
55
  }),
55
56
  );
56
57
 
57
- const buttonText = await page.$eval('button[data-test-trigger]', element => element.innerText);
58
+ const buttonText = await page.$eval('button[data-test-trigger]', (element) => element.innerText);
58
59
  expect(buttonText.trim()).toBe('Close all');
59
60
  });
60
61
 
@@ -67,7 +68,7 @@ describe('script: accordion', () => {
67
68
  }),
68
69
  );
69
70
 
70
- const ariaExpanded = await page.$eval('button[data-test-trigger]', element => element.getAttribute('aria-expanded'));
71
+ const ariaExpanded = await page.$eval('button[data-test-trigger]', (element) => element.getAttribute('aria-expanded'));
71
72
  expect(ariaExpanded).toBe('true');
72
73
  });
73
74
 
@@ -76,10 +77,11 @@ describe('script: accordion', () => {
76
77
 
77
78
  await page.click('button[data-test-trigger]');
78
79
 
79
- const openElements = await page.$$eval('.ons-js-details', nodes => nodes.filter(node => node.open));
80
- expect(openElements[0]).not.toBe(undefined);
81
- expect(openElements[1]).not.toBe(undefined);
82
- expect(openElements[2]).not.toBe(undefined);
80
+ const detailsElementStates = await page.$$eval('.ons-js-details', (nodes) =>
81
+ nodes.map((node) => node.classList.contains('ons-details--open')),
82
+ );
83
+
84
+ expect(detailsElementStates).toEqual([true, true, true]);
83
85
  });
84
86
 
85
87
  it('closes all items when accordion `allbutton` is clicked twice', async () => {
@@ -88,23 +90,24 @@ describe('script: accordion', () => {
88
90
  await page.click('button[data-test-trigger]');
89
91
  await page.click('button[data-test-trigger]');
90
92
 
91
- const openElements = await page.$$eval('.ons-js-details', nodes => nodes.filter(node => node.open));
92
- expect(openElements[0]).toBe(undefined);
93
- expect(openElements[1]).toBe(undefined);
94
- expect(openElements[2]).toBe(undefined);
93
+ const detailsElementStates = await page.$$eval('.ons-js-details', (nodes) =>
94
+ nodes.map((node) => node.classList.contains('ons-details--open')),
95
+ );
96
+
97
+ expect(detailsElementStates).toEqual([false, false, false]);
95
98
  });
96
99
 
97
100
  it('starts with the toggle all button labelled as "Open all"', async () => {
98
101
  await setTestPage('/test', renderComponent('accordion', EXAMPLE_ACCORDION_WITH_ALL_BUTTON));
99
102
 
100
- const buttonText = await page.$eval('button[data-test-trigger]', element => element.innerText);
103
+ const buttonText = await page.$eval('button[data-test-trigger]', (element) => element.innerText);
101
104
  expect(buttonText.trim()).toBe('Open all');
102
105
  });
103
106
 
104
107
  it('starts with the toggle all button aria-expanded set to false', async () => {
105
108
  await setTestPage('/test', renderComponent('accordion', EXAMPLE_ACCORDION_WITH_ALL_BUTTON));
106
109
 
107
- const ariaExpanded = await page.$eval('button[data-test-trigger]', element => element.getAttribute('aria-expanded'));
110
+ const ariaExpanded = await page.$eval('button[data-test-trigger]', (element) => element.getAttribute('aria-expanded'));
108
111
  expect(ariaExpanded).toBe('false');
109
112
  });
110
113
 
@@ -113,7 +116,7 @@ describe('script: accordion', () => {
113
116
 
114
117
  await page.click('button[data-test-trigger]');
115
118
 
116
- const buttonText = await page.$eval('button[data-test-trigger]', element => element.innerText);
119
+ const buttonText = await page.$eval('button[data-test-trigger]', (element) => element.innerText);
117
120
  expect(buttonText.trim()).toBe('Close all');
118
121
  });
119
122
 
@@ -122,7 +125,7 @@ describe('script: accordion', () => {
122
125
 
123
126
  await page.click('button[data-test-trigger]');
124
127
 
125
- const ariaExpanded = await page.$eval('button[data-test-trigger]', element => element.getAttribute('aria-expanded'));
128
+ const ariaExpanded = await page.$eval('button[data-test-trigger]', (element) => element.getAttribute('aria-expanded'));
126
129
  expect(ariaExpanded).toBe('true');
127
130
  });
128
131
 
@@ -133,7 +136,7 @@ describe('script: accordion', () => {
133
136
  await page.click('#example-accordion-2 .ons-details__heading');
134
137
  await page.click('#example-accordion-3 .ons-details__heading');
135
138
 
136
- const buttonText = await page.$eval('button[data-test-trigger]', element => element.innerText);
139
+ const buttonText = await page.$eval('button[data-test-trigger]', (element) => element.innerText);
137
140
  expect(buttonText.trim()).toBe('Close all');
138
141
  });
139
142
  });
@@ -62,7 +62,7 @@
62
62
  "text": "Areas (0)"
63
63
  },
64
64
  "value": "areas"
65
- }
65
+ }
66
66
  ]
67
67
  })
68
68
  }}
@@ -98,14 +98,14 @@
98
98
  "text": "Disability (67)"
99
99
  },
100
100
  "value": "disability"
101
- }
101
+ }
102
102
  ]
103
103
  })
104
104
  }}
105
105
  {% endset %}
106
106
 
107
107
  <div class="ons-grid">
108
- <div class="ons-grid__col ons-col-3@xs">
108
+ <div class="ons-grid__col ons-col-4@m">
109
109
  {{
110
110
  onsAccordion({
111
111
  "id": "accordion",
@@ -11,7 +11,7 @@
11
11
  & > .ons-card__title {
12
12
  margin-bottom: 0;
13
13
  }
14
- }
14
+ }
15
15
 
16
16
  &__link:hover {
17
17
  text-decoration-thickness: 3px;
@@ -7,7 +7,7 @@
7
7
  {% set fields %}
8
8
  {% if params.checkboxesLabel is defined %}
9
9
  <p class="ons-checkboxes__label{{ " " + params.checkboxesLabelClasses if params.checkboxesLabelClasses }}">{{ params.checkboxesLabel }}</p>
10
- {% endif %}
10
+ {% endif %}
11
11
  {% set hasOther = false %}
12
12
  {% for checkbox in params.checkboxes %}
13
13
  {% if checkbox.other %}
@@ -82,7 +82,7 @@
82
82
  "text": "Areas (0)"
83
83
  },
84
84
  "value": "areas"
85
- }
85
+ }
86
86
  ]
87
87
  })
88
88
  }}
@@ -80,7 +80,7 @@
80
80
  "text": "Areas (0)"
81
81
  },
82
82
  "value": "areas"
83
- }
83
+ }
84
84
  ]
85
85
  })
86
86
  }}
@@ -28,7 +28,7 @@
28
28
  {% set acceptedText = 'You have accepted all additional cookies.' %}
29
29
  {% set rejectedText = 'You have rejected all additional cookies.' %}
30
30
  {% set confirmationButtonText = 'Hide' %}
31
- {% set contextSuffix = 'this message' %}
31
+ {% set contextSuffix = 'cookie message' %}
32
32
  {% set beforeLinkPreferencesURL = 'You can' %}
33
33
  {% set afterLinkPreferencesURL = 'change your cookie preferences</a> at any time.' %}
34
34
  {% set beforeLinkStatementText = '<p>Cookies are small files stored on your device when you visit a website. We use some essential cookies to make this website work.</p><p>We would like to set' %}
@@ -215,7 +215,7 @@ describe('macro: cookies-banner', () => {
215
215
 
216
216
  faker.renderComponent('cookies-banner', {});
217
217
 
218
- expect(buttonSpy.occurrences[2].buttonContext).toBe('this message');
218
+ expect(buttonSpy.occurrences[2].buttonContext).toBe('cookie message');
219
219
  });
220
220
 
221
221
  it('has `container--wide` class when `wide` is true', () => {
@@ -1,75 +1,81 @@
1
1
  $details-caret-width: 1.5rem;
2
2
 
3
3
  .ons-details {
4
- &__heading {
5
- color: var(--ons-color-text-link);
6
- cursor: pointer;
7
- display: inline-block;
8
- outline: none;
9
- padding: 0 0 0 $details-caret-width;
10
- pointer-events: initial;
11
- position: relative;
12
-
13
- &::marker,
14
- &::-webkit-details-marker {
15
- display: none;
16
- }
17
-
18
- &:focus {
19
- .ons-details__title {
20
- @extend %a-focus;
21
- // extend details focus background behind caret
22
- margin-left: -$details-caret-width;
23
- padding-left: $details-caret-width;
24
- }
25
- .ons-details__icon .ons-icon {
26
- fill: var(--ons-color-text-link-focus);
4
+ &--initialised & {
5
+ &__heading {
6
+ color: var(--ons-color-text-link);
7
+ cursor: pointer;
8
+ display: inline-block;
9
+ outline: none;
10
+ padding: 0 0 0 $details-caret-width;
11
+ pointer-events: initial;
12
+ position: relative;
13
+
14
+ &::marker,
15
+ &::-webkit-details-marker {
16
+ display: none;
27
17
  }
28
- }
29
18
 
30
- &:hover:not(:focus) {
31
- color: var(--ons-color-text-link-hover);
32
- .ons-details__icon {
33
- fill: var(--ons-color-text-link-hover);
19
+ &:focus {
20
+ .ons-details__title {
21
+ @extend %a-focus;
22
+ // extend details focus background behind caret
23
+ margin-left: -$details-caret-width;
24
+ padding-left: $details-caret-width;
25
+ }
26
+ .ons-details__icon .ons-icon {
27
+ fill: var(--ons-color-text-link-focus);
28
+ }
34
29
  }
35
- .ons-details__title {
36
- text-decoration: underline solid var(--ons-color-text-link-hover) 2px;
30
+
31
+ &:hover:not(:focus) {
32
+ color: var(--ons-color-text-link-hover);
33
+ .ons-details__icon {
34
+ fill: var(--ons-color-text-link-hover);
35
+ }
36
+ .ons-details__title {
37
+ text-decoration: underline solid var(--ons-color-text-link-hover) 2px;
38
+ }
37
39
  }
38
40
  }
39
- }
40
41
 
41
- &__icon {
42
- display: inline-block;
43
- fill: var(--ons-color-text-link);
44
- height: $details-caret-width;
45
- left: -0.15rem;
46
- position: absolute;
47
- top: -0.2rem;
48
- width: $details-caret-width;
49
- }
42
+ &__icon {
43
+ display: inline-block;
44
+ fill: var(--ons-color-text-link);
45
+ height: $details-caret-width;
46
+ left: -0.15rem;
47
+ position: absolute;
48
+ top: -0.2rem;
49
+ width: $details-caret-width;
50
+ }
50
51
 
51
- &__title {
52
- display: inline-block;
53
- font-size: 1rem;
54
- font-weight: $font-weight-bold;
55
- margin-bottom: 0;
56
- text-underline-position: under;
57
- transform: translateY(-1px);
58
- }
52
+ &__content {
53
+ display: none;
54
+ }
59
55
 
60
- &__content {
61
- border-left: 4px solid var(--ons-color-borders-indent);
62
- display: block;
63
- margin: 1rem 0 0;
64
- padding: 0 0 0 1.3em;
56
+ &__title {
57
+ display: inline-block;
58
+ font-size: 1rem;
59
+ font-weight: $font-weight-bold;
60
+ margin-bottom: 0;
61
+ text-underline-position: under;
62
+ transform: translateY(-1px);
63
+ }
65
64
  }
66
65
 
67
- &[open] & {
66
+ &--open & {
68
67
  &__icon {
69
68
  left: -0.1rem;
70
69
  top: 0.2rem;
71
70
  transform: rotate(90deg);
72
71
  }
72
+
73
+ &__content {
74
+ border-left: 4px solid var(--ons-color-borders-indent);
75
+ display: block;
76
+ margin: 1rem 0 0;
77
+ padding: 0 0 0 1.3em;
78
+ }
73
79
  }
74
80
 
75
81
  &--accordion & {
@@ -110,12 +116,15 @@ $details-caret-width: 1.5rem;
110
116
  padding: 0;
111
117
  }
112
118
  }
113
- }
114
119
 
115
- .ons-details--accordion {
116
- &[open] {
120
+ &--accordion.ons-details--open {
117
121
  .ons-details__icon {
122
+ position: absolute;
118
123
  top: 1.2rem;
119
124
  }
120
125
  }
126
+
127
+ &__icon {
128
+ display: none;
129
+ }
121
130
  }
@@ -1,5 +1,5 @@
1
1
  {% macro onsDetails(params) %}
2
- <details
2
+ <div
3
3
  id="{{ params.id }}"
4
4
  class="ons-details ons-js-details{% if params.isAccordion %} ons-details--accordion{% endif %}{% if params.classes %} {{ params.classes }}{% endif %}"
5
5
  {% if params.group %} data-group="{{ params.group }}"{% endif %}
@@ -7,8 +7,8 @@
7
7
  {% if params.saveState %} data-save-state="true"{% endif %}
8
8
  {% if params.open %} data-open="true"{% endif %}
9
9
  >
10
- <summary
11
- class="ons-details__heading ons-js-details-heading"
10
+ <div
11
+ class="ons-details__heading ons-js-details-heading" role="button"
12
12
  {% if params.headingAttributes %}{% for attribute, value in (params.headingAttributes.items() if params.headingAttributes is mapping and params.headingAttributes.items else params.headingAttributes) %}{{ attribute }}{% if value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
13
13
  >
14
14
  {% set titleTag = params.titleTag | default("h2") %}
@@ -20,11 +20,11 @@
20
20
  "iconType": "chevron"
21
21
  })
22
22
  }}</span>
23
- </summary>
23
+ </div>
24
24
  <div id="{{ params.id }}-content" class="ons-details__content ons-js-details-content"
25
25
  {% if params.contentAttributes %}{% for attribute, value in (params.contentAttributes.items() if params.contentAttributes is mapping and params.contentAttributes.items else params.contentAttributes) %}{{ attribute }}{% if value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
26
26
  >
27
27
  {{ params.content | safe }}{{ caller() if caller }}
28
28
  </div>
29
- </details>
29
+ </div>
30
30
  {% endmacro %}
@@ -40,10 +40,7 @@ describe('macro: details', () => {
40
40
  it('has provided title text', () => {
41
41
  const $ = cheerio.load(renderComponent('details', EXAMPLE_DETAILS_BASIC));
42
42
 
43
- const titleText = $('.ons-details__title')
44
- .first()
45
- .text()
46
- .trim();
43
+ const titleText = $('.ons-details__title').first().text().trim();
47
44
  expect(titleText).toBe('Title for details');
48
45
  });
49
46
 
@@ -62,9 +59,7 @@ describe('macro: details', () => {
62
59
  it('has provided content text', () => {
63
60
  const $ = cheerio.load(renderComponent('details', EXAMPLE_DETAILS_BASIC));
64
61
 
65
- const titleText = $('.ons-details__content')
66
- .text()
67
- .trim();
62
+ const titleText = $('.ons-details__content').text().trim();
68
63
  expect(titleText).toEqual(expect.stringContaining('Content for details'));
69
64
  });
70
65
 
@@ -143,9 +138,7 @@ describe('macro: details', () => {
143
138
  it('calls with content', () => {
144
139
  const $ = cheerio.load(renderComponent('details', { EXAMPLE_DETAILS_BASIC }, 'Example content...'));
145
140
 
146
- const content = $('.ons-details__content')
147
- .text()
148
- .trim();
141
+ const content = $('.ons-details__content').text().trim();
149
142
  expect(content).toEqual(expect.stringContaining('Example content...'));
150
143
  });
151
144
  });
@@ -6,7 +6,7 @@ async function initialiseDetailsEls() {
6
6
 
7
7
  if (detailsComponents.length && !accordionComponents.length) {
8
8
  const Details = (await import('./details')).default;
9
- detailsComponents.map(element => new Details(element));
9
+ detailsComponents.map((element) => new Details(element));
10
10
  }
11
11
  }
12
12
 
@@ -7,17 +7,25 @@ export default class Details {
7
7
  // Elements
8
8
  this.details = detailsElement;
9
9
  this.detailsHeader = this.details.querySelector('.ons-js-details-heading');
10
+ this.content = this.details.querySelector('.ons-js-details-content');
10
11
 
11
12
  // Initialise
12
13
  const detailsId = detailsElement.getAttribute('id');
13
14
 
15
+ this.details.setAttribute('role', 'group');
16
+ this.detailsHeader.setAttribute('role', 'link');
17
+ this.detailsHeader.setAttribute('aria-controls', detailsId);
18
+ this.detailsHeader.setAttribute('tabindex', 0);
19
+
14
20
  if (localStorage.getItem(detailsId) || this.open) {
15
21
  this.setOpen(true);
16
- this.details['setAttribute']('open', '');
22
+ } else {
23
+ this.setOpen(false);
17
24
  }
18
25
 
19
26
  this.detailsHeader.addEventListener('click', this.toggle.bind(this));
20
27
  this.detailsHeader.addEventListener('keydown', this.keyboardInteraction.bind(this));
28
+ this.details.classList.add('ons-details--initialised');
21
29
  }
22
30
 
23
31
  toggle(event) {
@@ -28,10 +36,14 @@ export default class Details {
28
36
  setOpen(open) {
29
37
  if (open !== this.isOpen) {
30
38
  const action = open ? 'Open' : 'Close';
39
+ const cls = open ? 'add' : 'remove';
31
40
  const openAttribute = open ? 'set' : 'remove';
32
41
 
33
42
  this.isOpen = open;
34
43
  this.details[`${openAttribute}Attribute`]('open', '');
44
+ this.details.classList[cls]('ons-details--open');
45
+ this.detailsHeader.setAttribute('aria-expanded', open);
46
+ this.content.setAttribute('aria-hidden', !open);
35
47
  this.detailsHeader.setAttribute('data-ga-action', `${action} panel`);
36
48
 
37
49
  if (this.onOpen && this.onClose) {
@@ -1,4 +1,4 @@
1
- import { renderComponent, setTestPage } from '../../tests/helpers/rendering';
1
+ import { renderComponent, renderTemplate, setTestPage } from '../../tests/helpers/rendering';
2
2
 
3
3
  const EXAMPLE_DETAILS_BASIC = {
4
4
  id: 'details-id',
@@ -6,6 +6,22 @@ const EXAMPLE_DETAILS_BASIC = {
6
6
  content: 'Content for details',
7
7
  };
8
8
 
9
+ const EXAMPLE_PAGE = `
10
+ ${renderComponent('details', {
11
+ id: 'details-id',
12
+ title: 'Title for details',
13
+ content: 'Content for details',
14
+ })}
15
+
16
+ ${renderComponent('details', {
17
+ id: 'details-id-2',
18
+ title: 'Title for details',
19
+ content: 'Content for details',
20
+ })}
21
+ `;
22
+
23
+ const RENDERED_EXAMPLE_PAGE = renderTemplate(EXAMPLE_PAGE);
24
+
9
25
  describe('script: details', () => {
10
26
  it('begins open when specified', async () => {
11
27
  await setTestPage(
@@ -16,8 +32,8 @@ describe('script: details', () => {
16
32
  }),
17
33
  );
18
34
 
19
- const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
20
- expect(openAttribute).toBe(true);
35
+ const detailsOpenClass = await page.$eval('.ons-js-details', (node) => node.classList.contains('ons-details--open'));
36
+ expect(detailsOpenClass).toBe(true);
21
37
  });
22
38
 
23
39
  describe('when the details heading is clicked to open the details', () => {
@@ -26,18 +42,34 @@ describe('script: details', () => {
26
42
  await page.click('.ons-js-details-heading');
27
43
  });
28
44
 
29
- it('sets the `open` attribute', async () => {
30
- const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
31
- expect(openAttribute).toBe(true);
45
+ it('sets the `open` attribute and adds the correct class', async () => {
46
+ const detailsOpenClass = await page.$eval('.ons-js-details', (node) => node.classList.contains('ons-details--open'));
47
+
48
+ expect(detailsOpenClass).toBe(true);
32
49
  });
33
50
 
34
51
  it('sets the `ga` attributes', async () => {
35
- const gaHeadingAttribute = await page.$eval('.ons-js-details-heading', element => element.getAttribute('data-ga-action'));
52
+ const gaHeadingAttribute = await page.$eval('.ons-js-details-heading', (element) => element.getAttribute('data-ga-action'));
36
53
 
37
54
  expect(gaHeadingAttribute).toBe('Open panel');
38
55
  });
39
56
  });
40
57
 
58
+ describe('when there is more than one details component and a details heading is clicked to open the details', () => {
59
+ beforeEach(async () => {
60
+ await setTestPage('/test', RENDERED_EXAMPLE_PAGE);
61
+ await page.click('#details-id > .ons-js-details-heading');
62
+ });
63
+
64
+ it('sets the `open` attribute and open class on the right component', async () => {
65
+ const detailsOpenClass = await page.$eval('#details-id', (node) => node.classList.contains('ons-details--open'));
66
+ const detailsOpenClass2 = await page.$eval('#details-id-2', (node) => node.classList.contains('ons-details--open'));
67
+
68
+ expect(detailsOpenClass).toBe(true);
69
+ expect(detailsOpenClass2).toBe(false);
70
+ });
71
+ });
72
+
41
73
  describe('when the details heading is focused', () => {
42
74
  beforeEach(async () => {
43
75
  await setTestPage('/test', renderComponent('details', EXAMPLE_DETAILS_BASIC));
@@ -50,8 +82,8 @@ describe('script: details', () => {
50
82
  });
51
83
 
52
84
  it('opens the details content', async () => {
53
- const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
54
- expect(openAttribute).toBe(true);
85
+ const detailsOpenClass = await page.$eval('.ons-js-details', (node) => node.classList.contains('ons-details--open'));
86
+ expect(detailsOpenClass).toBe(true);
55
87
  });
56
88
  });
57
89
 
@@ -61,8 +93,8 @@ describe('script: details', () => {
61
93
  });
62
94
 
63
95
  it('opens the details content', async () => {
64
- const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
65
- expect(openAttribute).toBe(true);
96
+ const detailsOpenClass = await page.$eval('.ons-js-details', (node) => node.classList.contains('ons-details--open'));
97
+ expect(detailsOpenClass).toBe(true);
66
98
  });
67
99
  });
68
100
  });
@@ -1,8 +1,7 @@
1
1
  {% from "components/details/_macro.njk" import onsDetails %}
2
2
  {% from "components/panel/_macro.njk" import onsPanel %}
3
3
 
4
- {%
5
- call onsDetails({
4
+ {% call onsDetails({
6
5
  "id": "details-example-with-warning",
7
6
  "title": "Need to answer separately from your household?"
8
7
  })
@@ -179,7 +179,7 @@
179
179
  {% endif %}
180
180
  {% if params.copyrightDeclaration %}
181
181
  <!-- Copyright -->
182
- <div class="ons-grid ons-grid--flex ons-grid--vertical-bottom ons-grid--between">
182
+ <div class="ons-grid ons-grid--flex ons-grid--vertical-bottom ons-grid--between">
183
183
  <div class="ons-grid__col">
184
184
  <p class="ons-u-fs-s ons-u-mb-no ons-footer__copyright">&copy; {{ params.copyrightDeclaration.copyright }} <br> {{ params.copyrightDeclaration.text }}</p>
185
185
  </div>
@@ -229,4 +229,8 @@
229
229
  margin-top: -5px !important;
230
230
  }
231
231
  }
232
+
233
+ .ons-btn {
234
+ top: 0 !important;
235
+ }
232
236
  }