@ons/design-system 72.10.8 → 72.10.10

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 (66) hide show
  1. package/README.md +9 -5
  2. package/components/accordion/accordion.js +3 -2
  3. package/components/announcement-banner/_announcement-banner.scss +24 -0
  4. package/components/announcement-banner/_macro.njk +33 -0
  5. package/components/announcement-banner/_macro.spec.js +106 -0
  6. package/components/announcement-banner/_test_examples.js +22 -0
  7. package/components/announcement-banner/example-banner-black.njk +12 -0
  8. package/components/announcement-banner/example-banner-red.njk +13 -0
  9. package/components/announcement-banner/example-banner-teal.njk +13 -0
  10. package/components/autosuggest/autosuggest.spec.js +2 -0
  11. package/components/autosuggest/autosuggest.ui.js +12 -7
  12. package/components/breadcrumbs/_breadcrumbs.scss +53 -0
  13. package/components/breadcrumbs/_macro.njk +33 -24
  14. package/components/breadcrumbs/_macro.spec.js +25 -0
  15. package/components/button/_button.scss +29 -1
  16. package/components/chart/_chart.scss +88 -0
  17. package/components/chart/_macro.njk +25 -6
  18. package/components/chart/_macro.spec.js +1178 -640
  19. package/components/chart/bar-chart.js +8 -1
  20. package/components/chart/chart-iframe-resize.js +2 -2
  21. package/components/chart/common-chart-options.js +9 -0
  22. package/components/chart/example-bar-chart-with-axis-min-and-max-values.njk +0 -1
  23. package/components/chart/example-bar-chart-with-point-range-and-reference-line-annotations.njk +4 -4
  24. package/components/chart/example-bar-chart.njk +0 -1
  25. package/components/chart/example-iframe-chart.njk +1 -1
  26. package/components/chart/range-annotations-options.js +1 -1
  27. package/components/download-resources/download-resources.spec.js +2 -0
  28. package/components/duration/example-duration-error-for-single-field.njk +0 -1
  29. package/components/duration/example-duration-error.njk +0 -1
  30. package/components/footer/_macro.spec.js +2 -2
  31. package/components/header/_macro.njk +5 -16
  32. package/components/header/example-header-button-and-navigation.njk +133 -0
  33. package/components/header/example-header-external-with-navigation-and-search.njk +1 -1
  34. package/components/hero/_hero.scss +17 -22
  35. package/components/hero/_macro.njk +1 -1
  36. package/components/hero/_macro.spec.js +1 -1
  37. package/components/hero/example-hero-dark-with-external-breadcrumbs.njk +194 -0
  38. package/components/hero/example-hero-default-with-external-breadcrumbs.njk +201 -0
  39. package/components/hero/example-hero-grey-with-external-breadcrumbs.njk +243 -0
  40. package/components/hero/example-hero-navy-blue-with-external-breadcrumbs.njk +200 -0
  41. package/components/hero/example-hero-pale-blue-with-external-breadcrumbs.njk +201 -0
  42. package/components/icon/_macro.njk +1 -1
  43. package/components/mutually-exclusive/mutually-exclusive.js +3 -1
  44. package/components/navigation/_macro.njk +11 -16
  45. package/components/navigation/_navigation.scss +24 -0
  46. package/components/radios/clear-radios.js +4 -2
  47. package/components/relationships/relationships.js +4 -2
  48. package/components/table/_macro.njk +107 -112
  49. package/components/table/_macro.spec.js +35 -44
  50. package/components/table/_table.scss +0 -12
  51. package/components/table/example-table-sortable.njk +1 -1
  52. package/components/tabs/example-tabs-details.njk +1 -1
  53. package/components/textarea/_macro.njk +1 -0
  54. package/components/textarea/_macro.spec.js +1 -0
  55. package/components/timeout-panel/timeout-panel.spec.js +1 -1
  56. package/components/video/video.js +2 -0
  57. package/css/main.css +1 -1
  58. package/js/timeout.js +9 -6
  59. package/layout/_template.njk +13 -0
  60. package/package.json +6 -6
  61. package/scripts/main.es5.js +4 -2
  62. package/scripts/main.js +4 -2
  63. package/scss/main.scss +1 -0
  64. package/scss/vars/_colors.scss +3 -0
  65. package/scss/vars/_forms.scss +11 -0
  66. package/components/table/example-table-scrollable.njk +0 -158
@@ -19,120 +19,115 @@
19
19
  {% endfor %}
20
20
  {% endfor %}
21
21
 
22
- {% set table %}
23
- <table
24
- {% if params.id %}id="{{ params.id }}"{% endif %}
25
- class="ons-table{{ ' ' + params.tableClasses if params.tableClasses else '' }}{% if hasRowSpan %}{{ ' ' }}ons-table--has-rowspan{% endif %}{% if variants %}{% if variants is not string %}{% for variant in variants %}{{ ' ' }}ons-table--{{ variant }}{% endfor %}{% else %}{{ ' ' }}ons-table--{{ variants }}{% endif %}{% endif %}"
26
- {% if params.sortBy and 'sortable' in variants %}
27
- data-aria-sort="{{ params.sortBy }}" data-aria-asc="{{ params.ariaAsc }}" data-aria-desc="{{ params.ariaDesc }}"
28
- {% endif %}
22
+ <div class="ons-table-scrollable ons-table-scrollable--on">
23
+ <div
24
+ class="ons-table-scrollable__content"
25
+ tabindex="0"
26
+ role="region"
27
+ aria-label="{{ params.caption }}. {{ params.ariaLabel | default('Scrollable table') }}"
29
28
  >
30
- {% if params.caption %}
31
- <caption class="ons-table__caption{{ " ons-u-vh" if params.hideCaption }}">
32
- {{ params.caption }}
33
- </caption>
34
- {% endif %}
35
- <thead class="ons-table__head">
36
- {# Uses thList if multiple-row headers, otherwise wrap single ths array into a default group #}
37
- {% if params.thList %}
38
- {% set thGroups = params.thList %}
39
- {% else %}
40
- {% set thGroups = [ { ths: params.ths } ] %}
29
+ <table
30
+ {% if params.id %}id="{{ params.id }}"{% endif %}
31
+ class="ons-table{{ ' ' + params.tableClasses if params.tableClasses else '' }}{% if hasRowSpan %}{{ ' ' }}ons-table--has-rowspan{% endif %}{% if variants %}{% if variants is not string %}{% for variant in variants %}{{ ' ' }}ons-table--{{ variant }}{% endfor %}{% else %}{{ ' ' }}ons-table--{{ variants }}{% endif %}{% endif %}"
32
+ {% if params.sortBy and 'sortable' in variants %}
33
+ data-aria-sort="{{ params.sortBy }}" data-aria-asc="{{ params.ariaAsc }}" data-aria-desc="{{ params.ariaDesc }}"
41
34
  {% endif %}
42
- {% for headerCols in thGroups %}
43
- <tr class="ons-table__row">
44
- {% for th in headerCols.ths %}
45
- <th
46
- scope="col"
47
- class="ons-table__header{{ ' ' + th.thClasses if th.thClasses else '' }}{{ ' ons-table__header--numeric' if th.numeric }}"
48
- {% if th.colspan %}colspan="{{ th.colspan }}"{% endif %}
49
- {% if th.rowspan %}rowspan="{{ th.rowspan }}"{% endif %}
50
- {% if 'sortable' in variants %}aria-sort="{{ th.ariaSort | default('none') }}"{% endif %}
51
- {% if th.widthPercentage %}width="{{ th.widthPercentage }}%"{% endif %}
52
- >
53
- <span class="ons-table__header-text">{{ th.value | safe }}</span>
54
- {% if 'sortable' in variants %}
55
- {{-
56
- onsIcon({
57
- "iconType": "sort-sprite",
58
- "id": th.value | replace(' ', '-'),
59
- "classes": 'ons-u-d-no'
60
- })
61
- -}}
62
- {% endif %}
63
- </th>
64
- {% endfor %}
65
- </tr>
66
- {% endfor %}
67
- </thead>
68
- <tbody class="ons-table__body">
69
- {% for tr in params.trs %}
70
- <tr class="ons-table__row{{ ' ons-table__row--highlight' if tr.highlight }}" {% if tr.id %}id="{{ tr.id }}"{% endif %}>
71
- {% for td in tr.tds %}
72
- {% if td.heading == true %}
73
- {% set openingTag = '<th' %}
74
- {% set closingTag = '</th>' %}
75
- {% else %}
76
- {% set openingTag = '<td' %}
77
- {% set closingTag = '</td>' %}
78
- {% endif %}
79
- {% set isFirstRow = loop.index == 0 and td.rowspan %}
80
- {% set rowSpan = isFirstRow and loop.index0 == rowspanCount %}
81
- {{ openingTag | safe }}
82
- class="ons-table__cell{{ ' ' + td.tdClasses if td.tdClasses else '' }}{{ ' ons-table__cell--numeric' if td.numeric }}"
83
- {% if td.id %}id="{{ td.id }}"{% endif %}
84
- {% if td.data %}{{ ' ' }}data-th="{{ td.data }}"{% endif %}
85
- {% if td.colspan %}colspan="{{ td.colspan }}"{% endif %}
86
- {% if td.rowspan %}rowspan="{{ td.rowspan }}"{% endif %}
87
- {% if td.dataSort %}{{ ' ' }}data-sort-value="{{ td.dataSort }}"{% endif %}
88
- {% if td.heading %}scope="row"{% endif %}
89
- >
90
- {% if td.form %}
91
- <form action="{{ td.form.action }}" method="{{ td.form.method | default('POST') }}">
92
- {{ onsButton(td.form.button) }}
93
- {% if td.form.hiddenFormField %}
94
- {% for hiddenField in td.form.hiddenFormField %}
95
- <input
96
- type="hidden"
97
- {% if hiddenField.name %}name="{{ hiddenField.name }}"{% endif %}
98
- {% if hiddenField.value %}value="{{ hiddenField.value }}"{% endif %}
99
- />
100
- {% endfor %}
101
- {% endif %}
102
- </form>
103
- {% endif %}
104
- {% if td.value %}
105
- {{ td.value | safe }}
106
- {% endif %}
107
- {{ closingTag | safe }}
108
- {% endfor %}
109
- </tr>
110
- {% endfor %}
111
- </tbody>
112
- {% if params.tfoot %}
113
- <tfoot class="ons-table__foot">
114
- <tr class="ons-table__row">
115
- {% for tfootCell in params.tfoot %}
116
- <td class="ons-table__cell ons-u-fs-s">{{ tfootCell.value }}</td>
117
- {% endfor %}
118
- </tr>
119
- </tfoot>
120
- {% endif %}
121
- </table>
122
- {% endset %}
123
-
124
- {% if 'scrollable' in variants %}
125
- <div class="ons-table-scrollable ons-table-scrollable--on">
126
- <div
127
- class="ons-table-scrollable__content"
128
- tabindex="0"
129
- role="region"
130
- aria-label="{{ params.caption }}. {{ params.ariaLabel | default('Scrollable table') }}"
131
35
  >
132
- {{ table | safe }}
133
- </div>
36
+ {% if params.caption %}
37
+ <caption class="ons-table__caption{{ " ons-u-vh" if params.hideCaption }}">
38
+ {{ params.caption }}
39
+ </caption>
40
+ {% endif %}
41
+ <thead class="ons-table__head">
42
+ {# Uses thList if multiple-row headers, otherwise wrap single ths array into a default group #}
43
+ {% if params.thList %}
44
+ {% set thGroups = params.thList %}
45
+ {% else %}
46
+ {% set thGroups = [ { ths: params.ths } ] %}
47
+ {% endif %}
48
+ {% for headerCols in thGroups %}
49
+ <tr class="ons-table__row">
50
+ {% for th in headerCols.ths %}
51
+ <th
52
+ scope="col"
53
+ class="ons-table__header{{ ' ' + th.thClasses if th.thClasses else '' }}{{ ' ons-table__header--numeric' if th.numeric }}"
54
+ {% if th.colspan %}colspan="{{ th.colspan }}"{% endif %}
55
+ {% if th.rowspan %}rowspan="{{ th.rowspan }}"{% endif %}
56
+ {% if 'sortable' in variants %}aria-sort="{{ th.ariaSort | default('none') }}"{% endif %}
57
+ {% if th.widthPercentage %}width="{{ th.widthPercentage }}%"{% endif %}
58
+ >
59
+ <span class="ons-table__header-text">{{ th.value | safe }}</span>
60
+ {% if 'sortable' in variants %}
61
+ {{-
62
+ onsIcon({
63
+ "iconType": "sort-sprite",
64
+ "id": th.value | replace(' ', '-'),
65
+ "classes": 'ons-u-d-no'
66
+ })
67
+ -}}
68
+ {% endif %}
69
+ </th>
70
+ {% endfor %}
71
+ </tr>
72
+ {% endfor %}
73
+ </thead>
74
+ <tbody class="ons-table__body">
75
+ {% for tr in params.trs %}
76
+ <tr
77
+ class="ons-table__row{{ ' ons-table__row--highlight' if tr.highlight }}"
78
+ {% if tr.id %}id="{{ tr.id }}"{% endif %}
79
+ >
80
+ {% for td in tr.tds %}
81
+ {% if td.heading == true %}
82
+ {% set openingTag = '<th' %}
83
+ {% set closingTag = '</th>' %}
84
+ {% else %}
85
+ {% set openingTag = '<td' %}
86
+ {% set closingTag = '</td>' %}
87
+ {% endif %}
88
+ {% set isFirstRow = loop.index == 0 and td.rowspan %}
89
+ {% set rowSpan = isFirstRow and loop.index0 == rowspanCount %}
90
+ {{ openingTag | safe }}
91
+ class="ons-table__cell{{ ' ' + td.tdClasses if td.tdClasses else '' }}{{ ' ons-table__cell--numeric' if td.numeric }}"
92
+ {% if td.id %}id="{{ td.id }}"{% endif %}
93
+ {% if td.data %}{{ ' ' }}data-th="{{ td.data }}"{% endif %}
94
+ {% if td.colspan %}colspan="{{ td.colspan }}"{% endif %}
95
+ {% if td.rowspan %}rowspan="{{ td.rowspan }}"{% endif %}
96
+ {% if td.dataSort %}{{ ' ' }}data-sort-value="{{ td.dataSort }}"{% endif %}
97
+ {% if td.heading %}scope="row"{% endif %}
98
+ >
99
+ {% if td.form %}
100
+ <form action="{{ td.form.action }}" method="{{ td.form.method | default('POST') }}">
101
+ {{ onsButton(td.form.button) }}
102
+ {% if td.form.hiddenFormField %}
103
+ {% for hiddenField in td.form.hiddenFormField %}
104
+ <input
105
+ type="hidden"
106
+ {% if hiddenField.name %}name="{{ hiddenField.name }}"{% endif %}
107
+ {% if hiddenField.value %}value="{{ hiddenField.value }}"{% endif %}
108
+ />
109
+ {% endfor %}
110
+ {% endif %}
111
+ </form>
112
+ {% endif %}
113
+ {% if td.value %}
114
+ {{ td.value | safe }}
115
+ {% endif %}
116
+ {{ closingTag | safe }}
117
+ {% endfor %}
118
+ </tr>
119
+ {% endfor %}
120
+ </tbody>
121
+ {% if params.tfoot %}
122
+ <tfoot class="ons-table__foot">
123
+ <tr class="ons-table__row">
124
+ {% for tfootCell in params.tfoot %}
125
+ <td class="ons-table__cell ons-u-fs-s">{{ tfootCell.value }}</td>
126
+ {% endfor %}
127
+ </tr>
128
+ </tfoot>
129
+ {% endif %}
130
+ </table>
134
131
  </div>
135
- {% else %}
136
- {{ table | safe }}
137
- {% endif %}
132
+ </div>
138
133
  {% endmacro %}
@@ -55,6 +55,41 @@ describe('macro: table', () => {
55
55
  expect($('.ons-table').hasClass('another-extra-class')).toBe(true);
56
56
  });
57
57
 
58
+ it('renders "scrollable" container element', () => {
59
+ const $ = cheerio.load(renderComponent('table', EXAMPLE_TABLE));
60
+
61
+ expect($('.ons-table-scrollable').length).toBe(1);
62
+ });
63
+
64
+ it('renders "content" container element', () => {
65
+ const $ = cheerio.load(renderComponent('table', EXAMPLE_TABLE));
66
+
67
+ expect($('.ons-table-scrollable__content').length).toBe(1);
68
+ });
69
+
70
+ it('renders an appropriate `aria-label` attribute on the "content" container element', () => {
71
+ const $ = cheerio.load(
72
+ renderComponent('table', {
73
+ ...EXAMPLE_TABLE,
74
+ caption: 'Example table caption',
75
+ }),
76
+ );
77
+
78
+ expect($('.ons-table-scrollable__content').attr('aria-label')).toBe('Example table caption. Scrollable table');
79
+ });
80
+
81
+ it('renders a custom `aria-label` attribute on the "content" container element', () => {
82
+ const $ = cheerio.load(
83
+ renderComponent('table', {
84
+ ...EXAMPLE_TABLE,
85
+ caption: 'Example table caption',
86
+ ariaLabel: 'Special table',
87
+ }),
88
+ );
89
+
90
+ expect($('.ons-table-scrollable__content').attr('aria-label')).toBe('Example table caption. Special table');
91
+ });
92
+
58
93
  describe('header row', () => {
59
94
  it('renders header cells with expected text', () => {
60
95
  const $ = cheerio.load(renderComponent('table', EXAMPLE_TABLE));
@@ -496,50 +531,6 @@ describe('macro: table', () => {
496
531
  });
497
532
  });
498
533
 
499
- describe('scrollable variant', () => {
500
- const params = {
501
- ...EXAMPLE_TABLE,
502
- variants: ['scrollable'],
503
- caption: 'Example table caption',
504
- };
505
-
506
- it('has the "scrollable" variant class', () => {
507
- const $ = cheerio.load(renderComponent('table', params));
508
-
509
- expect($('.ons-table').hasClass('ons-table--scrollable')).toBe(true);
510
- });
511
-
512
- it('renders "scrollable" container element', () => {
513
- const $ = cheerio.load(renderComponent('table', params));
514
-
515
- expect($('.ons-table-scrollable').length).toBe(1);
516
- expect($('.ons-table-scrollable--on').length).toBe(1);
517
- });
518
-
519
- it('renders "content" container element', () => {
520
- const $ = cheerio.load(renderComponent('table', params));
521
-
522
- expect($('.ons-table-scrollable__content').length).toBe(1);
523
- });
524
-
525
- it('renders an appropriate `aria-label` attribute on the "content" container element', () => {
526
- const $ = cheerio.load(renderComponent('table', params));
527
-
528
- expect($('.ons-table-scrollable__content').attr('aria-label')).toBe('Example table caption. Scrollable table');
529
- });
530
-
531
- it('renders a custom `aria-label` attribute on the "content" container element', () => {
532
- const $ = cheerio.load(
533
- renderComponent('table', {
534
- ...params,
535
- ariaLabel: 'Special table',
536
- }),
537
- );
538
-
539
- expect($('.ons-table-scrollable__content').attr('aria-label')).toBe('Example table caption. Special table');
540
- });
541
- });
542
-
543
534
  describe('sortable variant', () => {
544
535
  const params = {
545
536
  ...EXAMPLE_TABLE,
@@ -116,12 +116,6 @@
116
116
  background: var(--ons-color-grey-75);
117
117
  border-radius: 20px;
118
118
  }
119
- &--on {
120
- .ons-table__header,
121
- .ons-table__cell {
122
- white-space: nowrap;
123
- }
124
- }
125
119
  &__content {
126
120
  overflow: visible;
127
121
  overflow-x: auto;
@@ -134,12 +128,6 @@
134
128
  outline: 3px solid transparent; // Add transparent outline because Windows High Contrast Mode doesn't show box-shadows
135
129
  outline-offset: 1px;
136
130
  }
137
- .ons-table__header,
138
- .ons-table__cell {
139
- @include mq('2xs', m) {
140
- white-space: nowrap;
141
- }
142
- }
143
131
  .ons-table__right-shadow,
144
132
  .ons-table__left-shadow {
145
133
  height: 100%;
@@ -3,7 +3,7 @@
3
3
  {{
4
4
  onsTable({
5
5
  "variants": 'sortable',
6
- "caption": "Javascript enhanced sortable table",
6
+ "caption": "JavaScript enhanced sortable table",
7
7
  "sortBy": "Sort by",
8
8
  "ariaAsc": "ascending",
9
9
  "ariaDesc": "descending",
@@ -127,7 +127,7 @@
127
127
  <p>estimates to meet this level of quality</p>
128
128
  <p>year after year</p>
129
129
  <p>to find out more about the dynamic</p>
130
- <p>population model visit the ons website</p>
130
+ <p>population model visit the ONS website</p>
131
131
  </div>"
132
132
  },
133
133
  {
@@ -9,6 +9,7 @@
9
9
  {% if params.label %}
10
10
  {{
11
11
  onsLabel({
12
+ "id": params.id ~ "-label",
12
13
  "for": params.id,
13
14
  "text": params.label.text,
14
15
  "description": params.label.description,
@@ -178,6 +178,7 @@ describe('macro: textarea', () => {
178
178
  faker.renderComponent('textarea', EXAMPLE_TEXTAREA);
179
179
 
180
180
  expect(labelSpy.occurrences).toContainEqual({
181
+ id: 'example-id-label',
181
182
  for: 'example-id',
182
183
  text: 'Please provide some feedback',
183
184
  description: 'For example, describe any difficulties you experienced in the use of this service',
@@ -137,7 +137,7 @@ describe('script: timeout panel', () => {
137
137
  });
138
138
  });
139
139
 
140
- describe('when Javascript is disabled', () => {
140
+ describe('when JavaScript is disabled', () => {
141
141
  beforeEach(async () => {
142
142
  const expiryTime = new Date(Date.now() + 1 * 1000);
143
143
  const expiryTimeInISOFormat = new Date(expiryTime).toISOString();
@@ -1,3 +1,4 @@
1
+ import DOMPurify from 'dompurify';
1
2
  export default class Video {
2
3
  constructor(component) {
3
4
  this.component = component;
@@ -30,6 +31,7 @@ export default class Video {
30
31
  }
31
32
  addDNTtoVimeoVideos() {
32
33
  let src = this.iframe.getAttribute('data-src');
34
+ src = DOMPurify.sanitize(src);
33
35
  if (src.includes('player.vimeo.com/video') && src.includes('?dnt=1') === false) {
34
36
  src += '?dnt=1';
35
37
  return src;