@ons/design-system 57.0.0 → 58.0.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.
Files changed (76) hide show
  1. package/components/autosuggest/_autosuggest.scss +16 -16
  2. package/components/breadcrumbs/_breadcrumbs.scss +2 -2
  3. package/components/browser-banner/_browser-banner.scss +5 -5
  4. package/components/button/_button.scss +62 -62
  5. package/components/call-to-action/_call-to-action.scss +1 -1
  6. package/components/checkboxes/_checkbox.scss +16 -16
  7. package/components/collapsible/_collapsible.scss +8 -8
  8. package/components/content-pagination/_content-pagination.scss +1 -1
  9. package/components/cookies-banner/_cookies-banner.scss +3 -3
  10. package/components/document-list/document-list.scss +10 -10
  11. package/components/download-resources/_download-resources.scss +5 -5
  12. package/components/external-link/_external-link.scss +4 -4
  13. package/components/feedback/_feedback.scss +3 -3
  14. package/components/field/_field.scss +1 -1
  15. package/components/find-a-support-centre/_find-a-support-centre.scss +1 -1
  16. package/components/footer/_footer.scss +7 -7
  17. package/components/header/_header.scss +26 -26
  18. package/components/hero/_hero.scss +4 -4
  19. package/components/input/_input-type.scss +5 -5
  20. package/components/input/_input.scss +13 -13
  21. package/components/label/_label.scss +1 -1
  22. package/components/lists/_list.scss +1 -1
  23. package/components/message/_message.scss +3 -3
  24. package/components/message-list/_message-list.scss +1 -1
  25. package/components/modal/_modal.scss +1 -1
  26. package/components/navigation/_macro.njk +1 -1
  27. package/components/navigation/_macro.spec.js +20 -2
  28. package/components/navigation/_navigation.scss +14 -14
  29. package/components/pagination/_pagination.scss +2 -2
  30. package/components/panel/_panel.scss +22 -22
  31. package/components/phase-banner/_phase-banner.scss +3 -3
  32. package/components/promotional-banner/_promo-banner.scss +5 -5
  33. package/components/question/_question.scss +4 -4
  34. package/components/quote/_quote.scss +2 -2
  35. package/components/radios/_radio.scss +6 -4
  36. package/components/related-content/_related-content.scss +2 -2
  37. package/components/relationships/_relationships.scss +2 -2
  38. package/components/section-navigation/_macro.njk +1 -1
  39. package/components/section-navigation/_section-navigation.scss +8 -8
  40. package/components/skip-to-content/_skip.scss +3 -3
  41. package/components/status/_status.scss +5 -5
  42. package/components/summary/_summary.scss +6 -6
  43. package/components/table/_table.scss +18 -18
  44. package/components/table-of-contents/_toc.scss +3 -3
  45. package/components/table-of-contents/toc.dom.js +2 -4
  46. package/components/tabs/_macro.njk +18 -5
  47. package/components/tabs/_macro.spec.js +54 -0
  48. package/components/tabs/_tabs.scss +57 -25
  49. package/components/tabs/tabs.js +35 -12
  50. package/components/tabs/tabs.spec.js +104 -10
  51. package/components/text-indent/_text-indent.scss +1 -1
  52. package/components/timeline/_timeline.scss +2 -2
  53. package/components/upload/_upload.scss +6 -6
  54. package/css/census.css +3 -3
  55. package/css/ids.css +3 -3
  56. package/css/main.css +3 -3
  57. package/css/print.css +1 -1
  58. package/package.json +1 -1
  59. package/scripts/main.es5.js +1 -1
  60. package/scripts/main.js +2 -2
  61. package/scss/base/_global.scss +7 -7
  62. package/scss/base/_typography.scss +2 -2
  63. package/scss/census.scss +1 -1
  64. package/scss/helpers/_functions.scss +0 -8
  65. package/scss/ids.scss +1 -1
  66. package/scss/overrides/hcm.scss +1 -1
  67. package/scss/overrides/rtl.scss +1 -1
  68. package/scss/patternlib.scss +10 -9
  69. package/scss/print.scss +7 -5
  70. package/scss/settings/_census.scss +24 -19
  71. package/scss/settings/_ids.scss +16 -12
  72. package/scss/utilities/_border.scss +1 -1
  73. package/scss/utilities/_colors.scss +1 -10
  74. package/scss/utilities/_grid.scss +3 -3
  75. package/scss/utilities/_typography.scss +1 -1
  76. package/scss/vars/_colors.scss +112 -99
@@ -1,12 +1,12 @@
1
1
  .ons-toc {
2
2
  &-container {
3
- border-bottom: 1px solid $color-grey-15;
3
+ border-bottom: 1px solid var(--ons-color-grey-15);
4
4
  margin-bottom: 2rem;
5
5
  padding-bottom: 1rem;
6
6
  }
7
7
 
8
8
  &__link-active {
9
- color: $color-text-link-hover;
10
- text-decoration: underline solid $color-text-link-hover 2px;
9
+ color: var(--ons-color-text-link-hover);
10
+ text-decoration: underline solid var(--ons-color-text-link-hover) 2px;
11
11
  }
12
12
  }
@@ -4,11 +4,9 @@ async function toc() {
4
4
  const toc = [...document.querySelectorAll('.ons-js-toc-container')];
5
5
 
6
6
  if (toc.length) {
7
- if ('IntersectionObserver' in window) {
8
- const Toc = (await import('./toc')).default;
7
+ const Toc = (await import('./toc')).default;
9
8
 
10
- toc.forEach(component => new Toc(component));
11
- }
9
+ toc.forEach(component => new Toc(component));
12
10
  }
13
11
  }
14
12
 
@@ -1,14 +1,27 @@
1
1
  {% macro onsTabs(params) %}
2
- <section class="ons-tabs">
3
- <h2 class="ons-tabs__title">{{params.title}}</h2>
2
+ {% set classes = 'ons-tabs' %}
3
+
4
+ {% set variantClasses %}
5
+ {% for variant in params.variants %}
6
+ {% set classes = classes ~ ' ons-tabs--' ~ variant %}
7
+ {% endfor %}
8
+ {% endset %}
9
+
10
+ <section class="{{ classes }}"
11
+ {% if params.noInitialActiveTab %}data-no-initial-active-tab="true"{% endif %}
12
+ >
13
+ {% set titleTag = params.titleTag | default("h2") %}
14
+ <{{ titleTag }} class="ons-tabs__title ons-u-fs-r--b ons-u-mt-no">{{ params.title }}</{{ titleTag }}>
15
+
4
16
  <ul class="ons-tabs__list">
5
17
  {% for tab in params.tabs %}
6
- <li id="tabId{{loop.index}}Item" class="ons-tab__list-item"><a href="#tabId{{loop.index}}" class="ons-tab" data-ga="click" data-ga-category="tabs" data-ga-action="Show: {{tab.title}}" data-ga-label="Show: {{tab.title}}">{{tab.title}}</a></li>
18
+ <li class="ons-tab__list-item"><a href="#{{ tab.id if tab.id else 'tabId' ~ loop.index }}" class="ons-tab" data-ga="click" data-ga-category="tabs" data-ga-action="Show: {{ tab.title }}" data-ga-label="Show: {{ tab.title }}">{{ tab.title }}</a></li>
7
19
  {% endfor %}
8
20
  </ul>
21
+
9
22
  {% for tab in params.tabs %}
10
- <section id="tabId{{loop.index}}" class="ons-tabs__panel">
11
- {{tab.content | safe}}
23
+ <section id="{{ tab.id if tab.id else 'tabId' ~ loop.index }}" class="ons-tabs__panel">
24
+ {{ tab.content | safe }}
12
25
  </section>
13
26
  {% endfor %}
14
27
  </section>
@@ -6,6 +6,22 @@ import axe from '../../tests/helpers/axe';
6
6
  import { renderComponent } from '../../tests/helpers/rendering';
7
7
 
8
8
  const EXAMPLE_TABS = {
9
+ title: 'Example tabs',
10
+ tabs: [
11
+ {
12
+ id: 'first-tab',
13
+ title: 'Tab 1',
14
+ content: 'Example content...',
15
+ },
16
+ {
17
+ id: 'second-tab',
18
+ title: 'Tab 2',
19
+ content: 'Some nested <strong>strong element</strong>...',
20
+ },
21
+ ],
22
+ };
23
+
24
+ const EXAMPLE_TABS_WITHOUT_TAB_IDS = {
9
25
  title: 'Example tabs',
10
26
  tabs: [
11
27
  {
@@ -27,6 +43,18 @@ describe('macro: tabs', () => {
27
43
  expect(results).toHaveNoViolations();
28
44
  });
29
45
 
46
+ it('has the provided variant classes', () => {
47
+ const $ = cheerio.load(
48
+ renderComponent('tabs', {
49
+ ...EXAMPLE_TABS,
50
+ variants: ['details', 'example-variant'],
51
+ }),
52
+ );
53
+
54
+ expect($('.ons-tabs').hasClass('ons-tabs--details')).toBe(true);
55
+ expect($('.ons-tabs').hasClass('ons-tabs--example-variant')).toBe(true);
56
+ });
57
+
30
58
  it('has the provided `title`', () => {
31
59
  const $ = cheerio.load(renderComponent('tabs', EXAMPLE_TABS));
32
60
 
@@ -37,6 +65,32 @@ describe('macro: tabs', () => {
37
65
  ).toBe('Example tabs');
38
66
  });
39
67
 
68
+ it('has title with provided tag override', () => {
69
+ const $ = cheerio.load(
70
+ renderComponent('tabs', {
71
+ ...EXAMPLE_TABS,
72
+ titleTag: 'h4',
73
+ }),
74
+ );
75
+
76
+ const titleTag = $('.ons-tabs__title')[0].tagName;
77
+ expect(titleTag).toBe('h4');
78
+ });
79
+
80
+ it('has the provided tab id attributes', () => {
81
+ const $ = cheerio.load(renderComponent('tabs', EXAMPLE_TABS));
82
+
83
+ expect($('.ons-tabs__panel:first').attr('id')).toBe('first-tab');
84
+ expect($('.ons-tabs__panel:last').attr('id')).toBe('second-tab');
85
+ });
86
+
87
+ it('has default tab id attribute values when identifiers are not provided', () => {
88
+ const $ = cheerio.load(renderComponent('tabs', EXAMPLE_TABS_WITHOUT_TAB_IDS));
89
+
90
+ expect($('.ons-tabs__panel:first').attr('id')).toBe('tabId1');
91
+ expect($('.ons-tabs__panel:last').attr('id')).toBe('tabId2');
92
+ });
93
+
40
94
  it('has expected label text in tab links', () => {
41
95
  const $ = cheerio.load(renderComponent('tabs', EXAMPLE_TABS));
42
96
 
@@ -18,9 +18,9 @@
18
18
  position: relative;
19
19
 
20
20
  &::after {
21
- background: $color-borders;
21
+ background: var(--ons-color-borders);
22
22
  bottom: 0;
23
- box-shadow: 0 1px 0 0 $color-page-light;
23
+ box-shadow: 0 1px 0 0 var(--ons-color-page-light);
24
24
  content: '';
25
25
  height: 1px;
26
26
  left: 0;
@@ -43,10 +43,10 @@
43
43
  }
44
44
 
45
45
  .ons-tab--row {
46
- background: $color-button-secondary;
47
- border: 1px solid $color-button-secondary;
46
+ background: var(--ons-color-button-secondary);
47
+ border: 1px solid var(--ons-color-button-secondary);
48
48
  border-radius: 3px 3px 0 0;
49
- color: $color-text;
49
+ color: var(--ons-color-text);
50
50
  display: inline-block;
51
51
  height: 2.55rem;
52
52
  line-height: 2.3rem;
@@ -57,42 +57,42 @@
57
57
  text-decoration: underline;
58
58
 
59
59
  &:hover {
60
- background-color: darken($color-button-secondary, 5%);
61
- border-color: darken($color-button-secondary, 5%);
62
- color: $color-text;
63
- text-decoration: underline solid $color-text 2px;
60
+ background-color: var(--ons-color-button-secondary-hover);
61
+ border-color: var(--ons-color-button-secondary-hover);
62
+ color: var(--ons-color-text);
63
+ text-decoration: underline solid var(--ons-color-text) 2px;
64
64
  }
65
65
 
66
66
  &:focus {
67
- background-color: $color-focus;
68
- border-bottom: 1px solid $color-borders;
69
- box-shadow: inset 0 0 0 9px $color-button-secondary,
70
- inset 17px 0 0 0 $color-button-secondary,
71
- inset -17px 0 0 0 $color-button-secondary,
72
- inset 0 -13px 0 0 $color-text-link-focus;
73
- color: $color-text-link-focus;
67
+ background-color: var(--ons-color-focus);
68
+ border-bottom: 1px solid var(--ons-color-borders);
69
+ box-shadow: inset 0 0 0 9px var(--ons-color-button-secondary),
70
+ inset 17px 0 0 0 var(--ons-color-button-secondary),
71
+ inset -17px 0 0 0 var(--ons-color-button-secondary),
72
+ inset 0 -13px 0 0 var(--ons-color-text-link-focus);
73
+ color: var(--ons-color-text-link-focus);
74
74
 
75
75
  // Add transparent outline because Windows High Contrast Mode doesn't show box-shadows
76
76
  outline: 3px solid transparent;
77
77
  outline-offset: 1px;
78
- text-decoration: underline solid $color-text 2px;
78
+ text-decoration: underline solid var(--ons-color-text) 2px;
79
79
  }
80
80
 
81
81
  // Tab when selected
82
82
  &[aria-selected='true'] {
83
- background-color: $color-page-light;
83
+ background-color: var(--ons-color-page-light);
84
84
  border-bottom: none;
85
- border-color: $color-borders;
85
+ border-color: var(--ons-color-borders);
86
86
  border-radius: 3px 3px 0 0;
87
87
  text-decoration: none;
88
88
  z-index: 1;
89
89
 
90
90
  &:focus {
91
- background-color: $color-focus;
92
- box-shadow: inset 0 0 0 9px $color-page-light,
93
- inset 17px 0 0 0 $color-page-light,
94
- inset -17px 0 0 0 $color-page-light,
95
- inset 0 -13px 0 0 $color-text-link-focus;
91
+ background-color: var(--ons-color-focus);
92
+ box-shadow: inset 0 0 0 9px var(--ons-color-page-light),
93
+ inset 17px 0 0 0 var(--ons-color-page-light),
94
+ inset -17px 0 0 0 var(--ons-color-page-light),
95
+ inset 0 -13px 0 0 var(--ons-color-text-link-focus);
96
96
  text-decoration: none;
97
97
  }
98
98
  }
@@ -109,8 +109,40 @@
109
109
  }
110
110
 
111
111
  &:focus {
112
- box-shadow: 0 0 0 3px $color-page-light, 0 0 0 5px $color-text-link-focus, 0 0 0 8px $color-focus;
112
+ box-shadow: 0 0 0 3px var(--ons-color-page-light), 0 0 0 5px var(--ons-color-text-link-focus), 0 0 0 8px var(--ons-color-focus);
113
113
  outline: 3px solid transparent; // Add transparent outline because Windows High Contrast Mode doesn't show box-shadows
114
114
  z-index: 1;
115
115
  }
116
116
  }
117
+
118
+ .ons-tabs--details {
119
+ border-top: 1px solid --ons-color-borders;
120
+ margin: 0;
121
+
122
+ .ons-tab {
123
+ border-radius: 0;
124
+ border-top: none;
125
+ }
126
+
127
+ .ons-tab__list-item:first-child .ons-tab {
128
+ border-left: none;
129
+ }
130
+
131
+ .ons-tabs__title {
132
+ padding: 1rem 1rem 0;
133
+ }
134
+
135
+ .ons-tabs__list {
136
+ padding: 0 1rem;
137
+ }
138
+
139
+ .ons-tabs__list--row {
140
+ margin-bottom: -1px;
141
+ padding: 0;
142
+ }
143
+
144
+ .ons-tabs__panel {
145
+ margin-top: 1px;
146
+ padding: 1rem;
147
+ }
148
+ }
@@ -30,6 +30,8 @@ export default class Tabs {
30
30
  this.jsTabItemAsRowClass = 'ons-tab__list-item--row';
31
31
  this.jsTabAsListClass = 'ons-tab--row';
32
32
 
33
+ this.noInitialActiveTab = this.component.getAttribute('data-no-initial-active-tab');
34
+
33
35
  if (matchMediaUtil.hasMatchMedia()) {
34
36
  this.setupViewportChecks();
35
37
  } else {
@@ -39,10 +41,10 @@ export default class Tabs {
39
41
 
40
42
  // Set up checks for responsive functionality
41
43
  // The tabs will display as tabs for >40rem viewports
42
- // Tabs will display as a TOC list and show full content for <40rem viewports
43
- // Aria tags are added only for >40rem viewports
44
+ // Tabs will display as a TOC list and show full content for <740px viewports
45
+ // Aria tags are added only for >740px viewports
44
46
  setupViewportChecks() {
45
- this.viewport = matchMediaUtil('(min-width: 40rem)');
47
+ this.viewport = matchMediaUtil('(min-width: 740px)');
46
48
  this.viewport.addListener(this.checkViewport.bind(this));
47
49
  this.checkViewport();
48
50
  }
@@ -79,8 +81,12 @@ export default class Tabs {
79
81
  this.hideTab(tab);
80
82
  });
81
83
 
82
- const activeTab = this.getTab(window.location.hash) || this.tabs[0];
83
- this.showTab(activeTab);
84
+ if (!this.noInitialActiveTab) {
85
+ const activeTab = this.getTab(window.location.hash) || this.tabs[0];
86
+ this.showTab(activeTab);
87
+ }
88
+
89
+ this.ensureTabIndexExists();
84
90
 
85
91
  this.component.boundOnHashChange = this.onHashChange.bind(this);
86
92
  window.addEventListener('hashchange', this.component.boundOnHashChange, true);
@@ -124,9 +130,10 @@ export default class Tabs {
124
130
  return;
125
131
  }
126
132
 
127
- const previousTab = this.getCurrentTab();
128
-
129
- this.hideTab(previousTab);
133
+ const currentTab = this.getCurrentTab();
134
+ if (!!currentTab) {
135
+ this.hideTab(currentTab);
136
+ }
130
137
  this.showTab(tabWithHash);
131
138
  tabWithHash.focus();
132
139
  }
@@ -177,9 +184,24 @@ export default class Tabs {
177
184
  e.preventDefault();
178
185
  const newTab = e.target;
179
186
  const currentTab = this.getCurrentTab();
180
- this.hideTab(currentTab);
181
- this.showTab(newTab);
182
- this.createHash(newTab);
187
+
188
+ if (!!currentTab) {
189
+ this.hideTab(currentTab);
190
+ }
191
+
192
+ if (!this.noInitialActiveTab || newTab !== currentTab) {
193
+ this.showTab(newTab);
194
+ this.createHash(newTab);
195
+ }
196
+
197
+ this.ensureTabIndexExists();
198
+ }
199
+
200
+ ensureTabIndexExists() {
201
+ // Ensure that at least the first tab has a tab index when all tabs are hidden.
202
+ if (!this.tabs.find(tab => tab.getAttribute('tabindex') === '0')) {
203
+ this.tabs[0].setAttribute('tabindex', '0');
204
+ }
183
205
  }
184
206
 
185
207
  createHash(tab) {
@@ -220,7 +242,8 @@ export default class Tabs {
220
242
  }
221
243
 
222
244
  getPanel(tab) {
223
- const panel = this.component.querySelector(this.getHref(tab));
245
+ const panelSelector = this.getHref(tab).replace(/\./g, '\\.');
246
+ const panel = this.component.querySelector(panelSelector);
224
247
  return panel;
225
248
  }
226
249
 
@@ -7,20 +7,28 @@ const EXAMPLE_TABS = {
7
7
  title: 'Example tabs',
8
8
  tabs: [
9
9
  {
10
+ id: 'tab.id.1',
10
11
  title: 'Tab 1',
11
12
  content: 'First content...',
12
13
  },
13
14
  {
15
+ id: 'tab.id.2',
14
16
  title: 'Tab 2',
15
17
  content: 'Second content...',
16
18
  },
17
19
  {
20
+ id: 'tab.id.3',
18
21
  title: 'Tab 3',
19
22
  content: 'Third content...',
20
23
  },
21
24
  ],
22
25
  };
23
26
 
27
+ const EXAMPLE_TABS_WITH_NO_INITIAL_ACTIVE_TAB = {
28
+ ...EXAMPLE_TABS,
29
+ noInitialActiveTab: true,
30
+ };
31
+
24
32
  describe('script: tabs', () => {
25
33
  afterEach(async () => {
26
34
  // Clear viewport size and browser emulation after each test.
@@ -47,7 +55,7 @@ describe('script: tabs', () => {
47
55
  it('has "aria-controls" assigned to each tab with the corresponding panel id', async () => {
48
56
  const ariaControlsValues = await page.$$eval('.ons-tab', nodes => nodes.map(node => node.getAttribute('aria-controls')));
49
57
 
50
- expect(ariaControlsValues).toEqual(['tabId1', 'tabId2', 'tabId3']);
58
+ expect(ariaControlsValues).toEqual(['tab.id.1', 'tab.id.2', 'tab.id.3']);
51
59
  });
52
60
 
53
61
  it('has "aria-selected" assigned to the first tab', async () => {
@@ -78,7 +86,7 @@ describe('script: tabs', () => {
78
86
 
79
87
  describe('when a tab is clicked', () => {
80
88
  beforeEach(async () => {
81
- await page.focus('#tabId2Item a');
89
+ await page.focus('a[href="#tab.id.2"]');
82
90
  await page.keyboard.press('Enter');
83
91
  });
84
92
 
@@ -89,13 +97,13 @@ describe('script: tabs', () => {
89
97
  });
90
98
 
91
99
  it('has the "aria-selected" attribute', async () => {
92
- const ariaSelectedValue = await page.$eval('#tabId2Item a', node => node.getAttribute('aria-selected'));
100
+ const ariaSelectedValue = await page.$eval('a[href="#tab.id.2"]', node => node.getAttribute('aria-selected'));
93
101
 
94
102
  expect(ariaSelectedValue).toBe('true');
95
103
  });
96
104
 
97
105
  it('has the "ons-tab--selected" class assigned', async () => {
98
- const hasClass = await page.$eval('#tabId2Item a', node => node.classList.contains('ons-tab--selected'));
106
+ const hasClass = await page.$eval('a[href="#tab.id.2"]', node => node.classList.contains('ons-tab--selected'));
99
107
 
100
108
  expect(hasClass).toBe(true);
101
109
  });
@@ -111,21 +119,21 @@ describe('script: tabs', () => {
111
119
 
112
120
  describe('when the right arrow key is pressed', () => {
113
121
  it('focuses the next tab', async () => {
114
- await page.focus('#tabId2Item a');
122
+ await page.focus('a[href="#tab.id.2"]');
115
123
  await page.keyboard.press('ArrowRight');
116
124
 
117
- const activeElementId = await page.evaluate(() => document.activeElement.parentElement.id);
118
- expect(activeElementId).toBe('tabId3Item');
125
+ const activeElement = await page.evaluate(() => document.activeElement.innerText);
126
+ expect(activeElement).toBe('Tab 3');
119
127
  });
120
128
  });
121
129
 
122
130
  describe('when the left arrow key is pressed', () => {
123
131
  it('focuses the previous tab', async () => {
124
- await page.focus('#tabId2Item a');
132
+ await page.focus('a[href="#tab.id.2"]');
125
133
  await page.keyboard.press('ArrowLeft');
126
134
 
127
- const activeElementId = await page.evaluate(() => document.activeElement.parentElement.id);
128
- expect(activeElementId).toBe('tabId1Item');
135
+ const activeElement = await page.evaluate(() => document.activeElement.innerText);
136
+ expect(activeElement).toBe('Tab 1');
129
137
  });
130
138
  });
131
139
  });
@@ -159,4 +167,90 @@ describe('script: tabs', () => {
159
167
  expect(hiddenPanelCount).toBe(0);
160
168
  });
161
169
  });
170
+
171
+ describe('when `data-no-initial-active-tab` is not present', () => {
172
+ beforeEach(async () => {
173
+ await setViewport(page, { width: 1650, height: 1050 });
174
+ await setTestPage('/test', renderComponent('tabs', EXAMPLE_TABS_WITH_NO_INITIAL_ACTIVE_TAB));
175
+ });
176
+
177
+ it('does not assign "aria-selected" to the first tab', async () => {
178
+ const ariaSelectedValue = await page.$eval('.ons-tab', node => node.getAttribute('aria-selected'));
179
+
180
+ expect(ariaSelectedValue).not.toBe('true');
181
+ });
182
+
183
+ it('does not assign the "ons-tab--selected" class to the first tab', async () => {
184
+ const hasClass = await page.$eval('.ons-tab', node => node.classList.contains('ons-tab--selected'));
185
+
186
+ expect(hasClass).toBe(false);
187
+ });
188
+
189
+ describe('when a tab is clicked', () => {
190
+ beforeEach(async () => {
191
+ await page.focus('a[href="#tab.id.1"]');
192
+ await page.keyboard.press('Enter');
193
+ });
194
+
195
+ it('is assigned a "tabindex" value', async () => {
196
+ const tabIndexValues = await page.$$eval('.ons-tab', nodes => nodes.map(node => node.getAttribute('tabindex')));
197
+
198
+ expect(tabIndexValues).toEqual(['0', '-1', '-1']);
199
+ });
200
+
201
+ it('has the "aria-selected" attribute', async () => {
202
+ const ariaSelectedValue = await page.$eval('a[href="#tab.id.1"]', node => node.getAttribute('aria-selected'));
203
+
204
+ expect(ariaSelectedValue).toBe('true');
205
+ });
206
+
207
+ it('has the "ons-tab--selected" class assigned', async () => {
208
+ const hasClass = await page.$eval('a[href="#tab.id.1"]', node => node.classList.contains('ons-tab--selected'));
209
+
210
+ expect(hasClass).toBe(true);
211
+ });
212
+
213
+ it('shows the corresponding panel', async () => {
214
+ const panelHiddenStates = await page.$$eval('.ons-tabs__panel', nodes =>
215
+ nodes.map(node => node.classList.contains('ons-tabs__panel--hidden')),
216
+ );
217
+
218
+ expect(panelHiddenStates).toEqual([false, true, true]);
219
+ });
220
+ });
221
+
222
+ describe('when a tab is clicked twice', () => {
223
+ beforeEach(async () => {
224
+ await page.focus('a[href="#tab.id.2"]');
225
+ await page.keyboard.press('Enter');
226
+ await page.keyboard.press('Enter');
227
+ });
228
+
229
+ it('is assigned a "tabindex" value', async () => {
230
+ const tabIndexValues = await page.$$eval('.ons-tab', nodes => nodes.map(node => node.getAttribute('tabindex')));
231
+
232
+ expect(tabIndexValues).toEqual(['0', '-1', '-1']);
233
+ });
234
+
235
+ it('does not have the "aria-selected" attribute', async () => {
236
+ const ariaSelectedValue = await page.$eval('a[href="#tab.id.2"]', node => node.getAttribute('aria-selected'));
237
+
238
+ expect(ariaSelectedValue).not.toBe('true');
239
+ });
240
+
241
+ it('does not have the "ons-tab--selected" class assigned', async () => {
242
+ const hasClass = await page.$eval('a[href="#tab.id.2"]', node => node.classList.contains('ons-tab--selected'));
243
+
244
+ expect(hasClass).toBe(false);
245
+ });
246
+
247
+ it('hides the corresponding panel', async () => {
248
+ const panelHiddenStates = await page.$$eval('.ons-tabs__panel', nodes =>
249
+ nodes.map(node => node.classList.contains('ons-tabs__panel--hidden')),
250
+ );
251
+
252
+ expect(panelHiddenStates).toEqual([true, true, true]);
253
+ });
254
+ });
255
+ });
162
256
  });
@@ -1,5 +1,5 @@
1
1
  .ons-text-indent {
2
- border-left: 4px solid $color-borders-indent;
2
+ border-left: 4px solid var(--ons-color-borders-indent);
3
3
  margin: 0 0 1rem;
4
4
  padding: 0 0 0 1.3em;
5
5
  }
@@ -3,7 +3,7 @@
3
3
  position: relative;
4
4
 
5
5
  &::before {
6
- border-left: 4px solid $color-black;
6
+ border-left: 4px solid var(--ons-color-black);
7
7
  content: '';
8
8
  height: 100%;
9
9
  left: 0;
@@ -17,7 +17,7 @@
17
17
  position: relative;
18
18
 
19
19
  &::before {
20
- background-color: $color-black;
20
+ background-color: var(--ons-color-black);
21
21
  content: '';
22
22
  height: 4px;
23
23
  left: -1.5rem;
@@ -1,17 +1,17 @@
1
1
  .ons-input--upload {
2
- background: $color-white;
3
- border: 1px solid $color-input-border;
2
+ background: var(--ons-color-white);
3
+ border: 1px solid var(--ons-color-input-border);
4
4
  border-radius: $input-radius;
5
5
  font-size: 1rem;
6
6
  padding: 0;
7
7
  width: 100%;
8
8
  &::-webkit-file-upload-button {
9
- background: $color-button-secondary;
9
+ background: var(--ons-color-button-secondary);
10
10
  border: 0;
11
11
  border-bottom-right-radius: 0;
12
- border-right: 1px solid $color-input-border;
12
+ border-right: 1px solid var(--ons-color-input-border);
13
13
  border-top-right-radius: 0;
14
- color: $color-text;
14
+ color: var(--ons-color-text);
15
15
  font-size: 1rem;
16
16
  outline: none;
17
17
  padding: 0.5rem 1rem;
@@ -20,7 +20,7 @@
20
20
  &:hover {
21
21
  cursor: pointer;
22
22
  &::-webkit-file-upload-button {
23
- border-right-color: $color-text-link-hover;
23
+ border-right-color: var(--ons-color-text-link-hover);
24
24
  cursor: pointer;
25
25
  }
26
26
  }