@ons/design-system 74.0.0-next.1 → 74.0.0-next.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 (107) hide show
  1. package/README.md +15 -3
  2. package/components/access-code/example-access-code-error.njk +1 -1
  3. package/components/access-code/example-access-code.njk +1 -1
  4. package/components/address-input/autosuggest.address.spec.js +23 -0
  5. package/components/autosuggest/autosuggest.ui.js +3 -0
  6. package/components/back-to-top/example-full-page-back-to-top.njk +1 -1
  7. package/components/breadcrumbs/_breadcrumbs.scss +4 -7
  8. package/components/breadcrumbs/_macro.njk +29 -25
  9. package/components/breadcrumbs/_macro.spec.js +39 -0
  10. package/components/breadcrumbs/example-breadcrumbs-wide.njk +52 -0
  11. package/components/chart/_chart.scss +0 -9
  12. package/components/chart/_macro.njk +96 -128
  13. package/components/chart/_macro.spec.js +43 -28
  14. package/components/chart/example-area-chart-with-axis-min-and-max-values.njk +6 -3
  15. package/components/chart/example-area-chart.njk +6 -3
  16. package/components/chart/example-bar-chart-with-annotations.njk +6 -3
  17. package/components/chart/example-bar-chart-with-axis-min-and-max-values.njk +6 -3
  18. package/components/chart/example-bar-chart-with-point-range-and-reference-line-annotations.njk +6 -3
  19. package/components/chart/example-bar-chart.njk +6 -3
  20. package/components/chart/example-bar-with-confidence-levels.njk +6 -3
  21. package/components/chart/example-clustered-bar-chart.njk +6 -3
  22. package/components/chart/example-clustered-column-chart.njk +6 -3
  23. package/components/chart/example-column-chart-with-annotations.njk +6 -3
  24. package/components/chart/example-column-chart-with-axis-min-and-max-values.njk +6 -3
  25. package/components/chart/example-column-chart-with-custom-reference-line-value.njk +6 -3
  26. package/components/chart/example-column-chart-with-range-annotations.njk +6 -3
  27. package/components/chart/example-column-chart-with-reference-line-annotations.njk +6 -3
  28. package/components/chart/example-column-chart.njk +6 -3
  29. package/components/chart/example-column-with-confidence-levels.njk +6 -3
  30. package/components/chart/example-column-with-line-chart.njk +6 -3
  31. package/components/chart/example-iframe-chart.njk +6 -3
  32. package/components/chart/example-line-chart-with-annotations.njk +6 -3
  33. package/components/chart/example-line-chart-with-axis-min-and-max-values.njk +6 -3
  34. package/components/chart/example-line-chart-with-custom-reference-line-value.njk +6 -3
  35. package/components/chart/example-line-chart-with-label-format.njk +6 -3
  36. package/components/chart/example-line-chart-with-markers.njk +6 -3
  37. package/components/chart/example-line-chart-with-range-annotations-inside.njk +6 -3
  38. package/components/chart/example-line-chart-with-range-annotations-outside-left-right.njk +6 -3
  39. package/components/chart/example-line-chart-with-range-annotations-outside-top-bottom.njk +6 -3
  40. package/components/chart/example-line-chart-with-reference-line-annotations.njk +6 -3
  41. package/components/chart/example-line-chart.njk +6 -3
  42. package/components/chart/example-scatter-chart-with-axis-min-and-max-values.njk +6 -3
  43. package/components/chart/example-scatter-chart.njk +6 -3
  44. package/components/chart/example-stacked-bar-chart.njk +6 -3
  45. package/components/chart/example-stacked-column-chart.njk +6 -3
  46. package/components/document-list/_macro.njk +2 -2
  47. package/components/document-list/_macro.spec.js +55 -0
  48. package/components/featured-article/_macro.njk +3 -37
  49. package/components/featured-article/example-featured-article-with-chart.njk +19 -14
  50. package/components/featured-article/example-featured-article-with-image.njk +12 -7
  51. package/components/featured-article/featured-article.scss +1 -1
  52. package/components/featured-article/macro.spec.js +44 -67
  53. package/components/figure/_figure.scss +31 -0
  54. package/components/figure/_macro.njk +98 -0
  55. package/components/figure/_macro.spec.js +520 -0
  56. package/components/figure/example-figure-heading-level-2.njk +34 -0
  57. package/components/figure/example-figure-with-div.njk +29 -0
  58. package/components/figure/example-figure-without-footer.njk +12 -0
  59. package/components/figure/example-figure-without-header.njk +24 -0
  60. package/components/figure/example-figure.njk +34 -0
  61. package/components/header/_header.scss +1 -3
  62. package/components/header/_macro.njk +8 -4
  63. package/components/header/_macro.spec.js +48 -0
  64. package/components/hero/_macro.njk +3 -2
  65. package/components/hero/_macro.spec.js +36 -0
  66. package/components/hero/example-hero-dark-wide.njk +17 -0
  67. package/components/hero/example-hero-dark-with-external-breadcrumbs.njk +17 -21
  68. package/components/hero/example-hero-default-full-width.njk +16 -0
  69. package/components/hero/example-hero-default-with-external-breadcrumbs.njk +165 -169
  70. package/components/hero/example-hero-grey-with-external-breadcrumbs.njk +207 -211
  71. package/components/hero/example-hero-navy-blue-with-external-breadcrumbs.njk +163 -167
  72. package/components/hero/example-hero-pale-blue-with-external-breadcrumbs.njk +165 -169
  73. package/components/image/_image.scss +0 -7
  74. package/components/image/_macro.njk +25 -14
  75. package/components/image/_macro.spec.js +122 -7
  76. package/components/image/example-image-with-figure-fields.njk +25 -0
  77. package/components/list/_macro.njk +1 -0
  78. package/components/list/_macro.spec.js +16 -0
  79. package/components/question/example-question-ccs.njk +1 -1
  80. package/components/question/example-question-fieldset.njk +1 -1
  81. package/components/question/example-question-interviewer-note.njk +1 -1
  82. package/components/question/example-question-no-fieldset.njk +1 -1
  83. package/components/relationships/example-relationships-error.njk +1 -1
  84. package/components/relationships/example-relationships-you.njk +1 -1
  85. package/components/relationships/example-relationships.njk +1 -1
  86. package/components/table/_macro.njk +138 -111
  87. package/components/table/_macro.spec.js +175 -16
  88. package/components/table/_table.scss +6 -1
  89. package/components/table/example-table-basic-no-caption.njk +46 -0
  90. package/components/table/example-table-basic-visually-hidden-caption.njk +47 -0
  91. package/components/table/example-table-with-figure-fields.njk +86 -0
  92. package/components/table/table.spec.js +2 -0
  93. package/components/table-of-contents/_macro.njk +6 -4
  94. package/components/table-of-contents/_macro.spec.js +43 -3
  95. package/components/table-of-contents/example-table-of-contents-ordered.njk +64 -0
  96. package/components/table-of-contents/example-table-of-contents-sticky-full-page-ordered.njk +156 -0
  97. package/components/table-of-contents/example-table-of-contents-sticky-full-page.njk +1 -1
  98. package/components/table-of-contents/table-of-contents.spec.js +4 -5
  99. package/css/main.css +1 -1
  100. package/layout/_template.njk +66 -46
  101. package/package.json +45 -36
  102. package/scripts/main.es5.js +3 -3
  103. package/scripts/main.js +2 -2
  104. package/scss/base/_global.scss +8 -0
  105. package/scss/main.scss +1 -0
  106. package/scss/objects/_page.scss +1 -1
  107. package/scss/objects/_spacing.scss +0 -4
@@ -23,7 +23,7 @@ layout: ~
23
23
  }
24
24
  %}
25
25
 
26
- {% block main %}
26
+ {% block mainContent %}
27
27
  {%
28
28
  call onsQuestion({
29
29
  "title": "<mark>Interviewer note:</mark>Who to interview",
@@ -23,7 +23,7 @@ layout: ~
23
23
  }
24
24
  %}
25
25
 
26
- {% block main %}
26
+ {% block mainContent %}
27
27
  {%
28
28
  call onsQuestion({
29
29
  "title": "How many visitors are staying overnight at 3 Severn Road on 13 May 2019?",
@@ -25,7 +25,7 @@ layout: ~
25
25
  }
26
26
  %}
27
27
 
28
- {% block main %}
28
+ {% block mainContent %}
29
29
 
30
30
  {%
31
31
  call onsPanel({
@@ -23,7 +23,7 @@ layout: ~
23
23
  }
24
24
  %}
25
25
 
26
- {% block main %}
26
+ {% block mainContent %}
27
27
  {%
28
28
  call onsQuestion({
29
29
  "title": "Joe Bloggs is your <strong>…</strong>",
@@ -23,7 +23,7 @@ layout: ~
23
23
  }
24
24
  %}
25
25
 
26
- {% block main %}
26
+ {% block mainContent %}
27
27
  {%
28
28
  call onsQuestion({
29
29
  "title": "Thinking of Joe Bloggs, Amanda Bloggs is their <strong>…</strong>",
@@ -1,121 +1,148 @@
1
1
  {% macro onsTable(params) %}
2
2
  {% from "components/button/_macro.njk" import onsButton %}
3
3
  {% from "components/icon/_macro.njk" import onsIcon %}
4
+ {% from "components/figure/_macro.njk" import onsFigure %}
4
5
  {% set variants = params.variants if params.variants %}
5
6
 
6
- <div class="ons-table-scrollable ons-table-scrollable--on">
7
- <div
8
- class="ons-table-scrollable__content"
9
- tabindex="0"
10
- role="region"
11
- aria-label="{{ params.caption }}. {{ params.ariaLabel | default('Scrollable table') }}"
12
- >
13
- {# Uses multiple loops to set the rowspan class so that it can work in both nunjucks and jinja2 environments due to the scoping rules of each language #}
14
- <table
15
- {% if params.id %}id="{{ params.id }}"{% endif %}
16
- class="ons-table{{ ' ' + params.tableClasses if params.tableClasses else '' }}{% for row in params.thList %}{% for th in row.ths %}{% if th.rowspan %}{{ ' ' }}ons-table--has-rowspan{% endif %}{% endfor %}{% endfor %}{% for row in params.trs %}{% for td in row.tds %}{% if td.rowspan %}{{ ' ' }}ons-table--has-rowspan{% endif %}{% endfor %}{% endfor %}{% if variants %}{% if variants is not string %}{% for variant in variants %}{{ ' ' }}ons-table--{{ variant }}{% endfor %}{% else %}{{ ' ' }}ons-table--{{ variants }}{% endif %}{% endif %}"
17
- {% if params.sortBy and 'sortable' in variants %}
18
- data-aria-sort="{{ params.sortBy }}" data-aria-asc="{{ params.ariaAsc }}" data-aria-desc="{{ params.ariaDesc }}"
19
- {% endif %}
7
+ {%
8
+ call onsFigure({
9
+ "useDivForRootElement": true,
10
+ "id": params.id,
11
+ "headingLevel": params.headingLevel,
12
+ "figureNumber": params.figureNumber,
13
+ "title": params.title,
14
+ "subtitle": params.subtitle,
15
+ "footnotes": params.footnotes,
16
+ "download": params.download,
17
+ "caption": params.sourceNote
18
+ })
19
+ %}
20
+ {% set tableClasses = "ons-table" %}
21
+
22
+ {# If there is no source note, footnotes or downloads after the table, add a bottom margin to the table to match the previous spacing #}
23
+ {# If there source note, footnotes or downloads after the table, the figure component handles the extra spacing #}
24
+ {% if not params.sourceNote and not params.footnotes and not params.download %}
25
+ {% set tableClasses = tableClasses + " ons-table--bottom-space" %}
26
+ {% endif %}
27
+
28
+ {% if params.tableClasses %}
29
+ {% set tableClasses = tableClasses + " " + params.tableClasses %}
30
+ {% endif %}
31
+
32
+ <div class="ons-table-scrollable ons-table-scrollable--on">
33
+ <div
34
+ class="ons-table-scrollable__content"
35
+ tabindex="0"
36
+ role="region"
37
+ {% if params.ariaLabel %}aria-label="{{ params.ariaLabel }}"{% endif %}
20
38
  >
21
- {% if params.caption %}
22
- <caption class="ons-table__caption{{ ' ons-u-vh' if params.hideCaption }}">
23
- {{ params.caption }}
24
- </caption>
25
- {% endif %}
26
- <thead class="ons-table__head">
27
- {# Uses thList if multiple-row headers, otherwise wrap single ths array into a default group #}
28
- {% if params.thList %}
29
- {% set thGroups = params.thList %}
30
- {% else %}
31
- {% set thGroups = [ { "ths": params.ths } ] %}
39
+ {# Uses multiple loops to set the rowspan class so that it can work in both nunjucks and jinja2 environments due to the scoping rules of each language #}
40
+ <table
41
+ class="{{ tableClasses }}{% for row in params.thList %}{% for th in row.ths %}{% if th.rowspan %}{{ ' ' }}ons-table--has-rowspan{% endif %}{% endfor %}{% endfor %}{% for row in params.trs %}{% for td in row.tds %}{% if td.rowspan %}{{ ' ' }}ons-table--has-rowspan{% endif %}{% endfor %}{% endfor %}{% if variants %}{% if variants is not string %}{% for variant in variants %}{{ ' ' }}ons-table--{{ variant }}{% endfor %}{% else %}{{ ' ' }}ons-table--{{ variants }}{% endif %}{% endif %}"
42
+ {% if params.sortBy and 'sortable' in variants %}
43
+ data-aria-sort="{{ params.sortBy }}" data-aria-asc="{{ params.ariaAsc }}" data-aria-desc="{{ params.ariaDesc }}"
32
44
  {% endif %}
33
- {% for headerCols in thGroups %}
34
- <tr class="ons-table__row">
35
- {% for th in headerCols.ths %}
36
- <th
37
- scope="col"
38
- class="ons-table__header ons-table__header--{{ th.valign | default('top') }}{{ ' ' + th.thClasses if th.thClasses else '' }}{{ ' ons-table__header--numeric' if th.numeric }}"
39
- {% if th.colspan %}colspan="{{ th.colspan }}"{% endif %}
40
- {% if th.rowspan %}rowspan="{{ th.rowspan }}"{% endif %}
41
- {% if 'sortable' in variants %}aria-sort="{{ th.ariaSort | default('none') }}"{% endif %}
42
- {% if th.widthPercentage %}width="{{ th.widthPercentage }}%"{% endif %}
43
- >
44
- <span class="ons-table__header-text">{{ th.value | safe }}</span>
45
- {% if 'sortable' in variants %}
46
- {{-
47
- onsIcon({
48
- "iconType": "sort-sprite",
49
- "id": th.value | replace(' ', '-'),
50
- "classes": 'ons-u-d-no'
51
- })
52
- -}}
53
- {% endif %}
54
- </th>
55
- {% endfor %}
56
- </tr>
57
- {% endfor %}
58
- </thead>
59
- <tbody class="ons-table__body">
60
- {% for tr in params.trs %}
61
- <tr
62
- class="ons-table__row{{ ' ons-table__row--highlight' if tr.highlight }}"
63
- {% if tr.id %}id="{{ tr.id }}"{% endif %}
64
- >
65
- {% for td in tr.tds %}
66
- {% if td.heading == true %}
67
- {% set openingTag = '<th' %}
68
- {% set closingTag = '</th>' %}
69
- {% else %}
70
- {% set openingTag = '<td' %}
71
- {% set closingTag = '</td>' %}
72
- {% endif %}
73
- {% set isFirstRow = loop.index == 0 and td.rowspan %}
74
- {% set rowSpan = isFirstRow and loop.index0 == rowspanCount %}
75
- {{ openingTag | safe }}
76
- class="ons-table__cell
77
- ons-table__cell--{{ td.valign | default('top') }}{{ ' ' + td.tdClasses if td.tdClasses else '' }}{{ ' ons-table__cell--numeric' if td.numeric }}"
78
- {% if td.id %}id="{{ td.id }}"{% endif %}
79
- {% if td.data %}{{ ' ' }}data-th="{{ td.data }}"{% endif %}
80
- {% if td.colspan %}colspan="{{ td.colspan }}"{% endif %}
81
- {% if td.rowspan %}rowspan="{{ td.rowspan }}"{% endif %}
82
- {% if td.dataSort %}{{ ' ' }}data-sort-value="{{ td.dataSort }}"{% endif %}
83
- {% if td.heading %}scope="row"{% endif %}
84
- >
85
- {% if td.form %}
86
- <form action="{{ td.form.action }}" method="{{ td.form.method | default('POST') }}">
87
- {{ onsButton(td.form.button) }}
88
- {% if td.form.hiddenFormField %}
89
- {% for hiddenField in td.form.hiddenFormField %}
90
- <input
91
- type="hidden"
92
- {% if hiddenField.name %}name="{{ hiddenField.name }}"{% endif %}
93
- {% if hiddenField.value %}value="{{ hiddenField.value }}"{% endif %}
94
- />
95
- {% endfor %}
45
+ >
46
+ {# Note that the caption is rendered inside the table element to be semantically correct, and we deliberately do not render it with the onsFigure caption option. We also have the option to visually hide it for the table. #}
47
+ {% if params.caption %}
48
+ <caption class="ons-table__caption{{ ' ons-u-vh' if params.hideCaption }}">
49
+ {{ params.caption }}
50
+ </caption>
51
+ {% endif %}
52
+ <thead class="ons-table__head">
53
+ {# Uses thList if multiple-row headers, otherwise wrap single ths array into a default group #}
54
+ {% if params.thList %}
55
+ {% set thGroups = params.thList %}
56
+ {% else %}
57
+ {% set thGroups = [ { "ths": params.ths } ] %}
58
+ {% endif %}
59
+ {% for headerCols in thGroups %}
60
+ <tr class="ons-table__row">
61
+ {% for th in headerCols.ths %}
62
+ <th
63
+ scope="col"
64
+ class="ons-table__header ons-table__header--{{ th.valign | default('top') }}{{ ' ' + th.thClasses if th.thClasses else '' }}{{ ' ons-table__header--numeric' if th.numeric }}"
65
+ {% if th.colspan %}colspan="{{ th.colspan }}"{% endif %}
66
+ {% if th.rowspan %}rowspan="{{ th.rowspan }}"{% endif %}
67
+ {% if 'sortable' in variants %}aria-sort="{{ th.ariaSort | default('none') }}"{% endif %}
68
+ {% if th.widthPercentage %}width="{{ th.widthPercentage }}%"{% endif %}
69
+ >
70
+ <span class="ons-table__header-text">{{ th.value | safe }}</span>
71
+ {% if 'sortable' in variants %}
72
+ {{-
73
+ onsIcon({
74
+ "iconType": "sort-sprite",
75
+ "id": th.value | replace(' ', '-'),
76
+ "classes": 'ons-u-d-no'
77
+ })
78
+ -}}
96
79
  {% endif %}
97
- </form>
98
- {% endif %}
99
- {% if td.value %}
100
- {{ td.value | safe }}
101
- {% endif %}
102
- {{ closingTag | safe }}
103
- {% endfor %}
104
- </tr>
105
- {% endfor %}
106
- </tbody>
107
- {% if params.tfoot %}
108
- <tfoot class="ons-table__foot">
109
- <tr class="ons-table__row">
110
- {% for tfootCell in params.tfoot %}
111
- <td class="ons-table__cell ons-table__cell--{{ tfootCell.valign | default('top') }} ons-u-fs-s">
112
- {{ tfootCell.value }}
113
- </td>
114
- {% endfor %}
115
- </tr>
116
- </tfoot>
117
- {% endif %}
118
- </table>
80
+ </th>
81
+ {% endfor %}
82
+ </tr>
83
+ {% endfor %}
84
+ </thead>
85
+ <tbody class="ons-table__body">
86
+ {% for tr in params.trs %}
87
+ <tr
88
+ class="ons-table__row{{ ' ons-table__row--highlight' if tr.highlight }}"
89
+ {% if tr.id %}id="{{ tr.id }}"{% endif %}
90
+ >
91
+ {% for td in tr.tds %}
92
+ {% if td.heading == true %}
93
+ {% set openingTag = '<th' %}
94
+ {% set closingTag = '</th>' %}
95
+ {% else %}
96
+ {% set openingTag = '<td' %}
97
+ {% set closingTag = '</td>' %}
98
+ {% endif %}
99
+ {% set isFirstRow = loop.index == 0 and td.rowspan %}
100
+ {% set rowSpan = isFirstRow and loop.index0 == rowspanCount %}
101
+ {{ openingTag | safe }}
102
+ class="ons-table__cell
103
+ ons-table__cell--{{ td.valign | default('top') }}{{ ' ' + td.tdClasses if td.tdClasses else '' }}{{ ' ons-table__cell--numeric' if td.numeric }}"
104
+ {% if td.id %}id="{{ td.id }}"{% endif %}
105
+ {% if td.data %}{{ ' ' }}data-th="{{ td.data }}"{% endif %}
106
+ {% if td.colspan %}colspan="{{ td.colspan }}"{% endif %}
107
+ {% if td.rowspan %}rowspan="{{ td.rowspan }}"{% endif %}
108
+ {% if td.dataSort %}{{ ' ' }}data-sort-value="{{ td.dataSort }}"{% endif %}
109
+ {% if td.heading %}scope="row"{% endif %}
110
+ >
111
+ {% if td.form %}
112
+ <form action="{{ td.form.action }}" method="{{ td.form.method | default('POST') }}">
113
+ {{ onsButton(td.form.button) }}
114
+ {% if td.form.hiddenFormField %}
115
+ {% for hiddenField in td.form.hiddenFormField %}
116
+ <input
117
+ type="hidden"
118
+ {% if hiddenField.name %}name="{{ hiddenField.name }}"{% endif %}
119
+ {% if hiddenField.value %}value="{{ hiddenField.value }}"{% endif %}
120
+ />
121
+ {% endfor %}
122
+ {% endif %}
123
+ </form>
124
+ {% endif %}
125
+ {% if td.value %}
126
+ {{ td.value | safe }}
127
+ {% endif %}
128
+ {{ closingTag | safe }}
129
+ {% endfor %}
130
+ </tr>
131
+ {% endfor %}
132
+ </tbody>
133
+ {% if params.tfoot %}
134
+ <tfoot class="ons-table__foot">
135
+ <tr class="ons-table__row">
136
+ {% for tfootCell in params.tfoot %}
137
+ <td class="ons-table__cell ons-table__cell--{{ tfootCell.valign | default('top') }} ons-u-fs-s">
138
+ {{ tfootCell.value }}
139
+ </td>
140
+ {% endfor %}
141
+ </tr>
142
+ </tfoot>
143
+ {% endif %}
144
+ </table>
145
+ </div>
119
146
  </div>
120
- </div>
147
+ {% endcall %}
121
148
  {% endmacro %}
@@ -7,6 +7,7 @@ import { mapAll } from '../../tests/helpers/cheerio';
7
7
  import { renderComponent, templateFaker } from '../../tests/helpers/rendering';
8
8
 
9
9
  const EXAMPLE_TABLE_MINIMAL = {
10
+ ariaLabel: 'Example table',
10
11
  ths: [],
11
12
  trs: [],
12
13
  };
@@ -32,7 +33,7 @@ describe('macro: table', () => {
32
33
  expect(results).toHaveNoViolations();
33
34
  });
34
35
 
35
- it('has the provided `id` attribute', () => {
36
+ it('has the provided `id` on the wrapping element', () => {
36
37
  const $ = cheerio.load(
37
38
  renderComponent('table', {
38
39
  ...EXAMPLE_TABLE,
@@ -40,7 +41,7 @@ describe('macro: table', () => {
40
41
  }),
41
42
  );
42
43
 
43
- expect($('.ons-table').attr('id')).toBe('example-table');
44
+ expect($('.ons-figure').attr('id')).toBe('example-table');
44
45
  });
45
46
 
46
47
  it('has additionally provided style classes', () => {
@@ -67,27 +68,15 @@ describe('macro: table', () => {
67
68
  expect($('.ons-table-scrollable__content').length).toBe(1);
68
69
  });
69
70
 
70
- it('renders an appropriate `aria-label` attribute on the "content" container element', () => {
71
+ it('renders the `aria-label` attribute on the "content" container element', () => {
71
72
  const $ = cheerio.load(
72
73
  renderComponent('table', {
73
74
  ...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
75
  ariaLabel: 'Special table',
87
76
  }),
88
77
  );
89
78
 
90
- expect($('.ons-table-scrollable__content').attr('aria-label')).toBe('Example table caption. Special table');
79
+ expect($('.ons-table-scrollable__content').attr('aria-label')).toBe('Special table');
91
80
  });
92
81
 
93
82
  describe('Vertical Alignment', () => {
@@ -680,4 +669,174 @@ describe('macro: table', () => {
680
669
  expect($('.ons-table__caption').hasClass('ons-u-vh')).toBe(true);
681
670
  });
682
671
  });
672
+
673
+ describe('bottom spacing', () => {
674
+ it('adds "ons-table--bottom-space" class when there are no footnotes, download or sourceNote', () => {
675
+ const $ = cheerio.load(renderComponent('table', EXAMPLE_TABLE));
676
+
677
+ expect($('.ons-table').hasClass('ons-table--bottom-space')).toBe(true);
678
+ });
679
+
680
+ it('does not add "ons-table--bottom-space" class when `sourceNote` is provided', () => {
681
+ const $ = cheerio.load(
682
+ renderComponent('table', {
683
+ ...EXAMPLE_TABLE,
684
+ sourceNote: 'Source: Office for National Statistics',
685
+ }),
686
+ );
687
+
688
+ expect($('.ons-table').hasClass('ons-table--bottom-space')).toBe(false);
689
+ });
690
+
691
+ it('does not add "ons-table--bottom-space" class when `footnotes` is provided', () => {
692
+ const $ = cheerio.load(
693
+ renderComponent('table', {
694
+ ...EXAMPLE_TABLE,
695
+ footnotes: {
696
+ title: 'Footnotes',
697
+ content: 'Data is seasonally adjusted.',
698
+ },
699
+ }),
700
+ );
701
+
702
+ expect($('.ons-table').hasClass('ons-table--bottom-space')).toBe(false);
703
+ });
704
+
705
+ it('does not add "ons-table--bottom-space" class when `download` is provided', () => {
706
+ const $ = cheerio.load(
707
+ renderComponent('table', {
708
+ ...EXAMPLE_TABLE,
709
+ download: {
710
+ title: 'Download this table',
711
+ itemsList: [
712
+ {
713
+ text: 'Table data (CSV, 2KB)',
714
+ url: '/data/table.csv',
715
+ download: 'file',
716
+ },
717
+ ],
718
+ },
719
+ }),
720
+ );
721
+
722
+ expect($('.ons-table').hasClass('ons-table--bottom-space')).toBe(false);
723
+ });
724
+ });
725
+
726
+ describe('figure wrapper', () => {
727
+ it('renders with a <div> root element instead of <figure>', () => {
728
+ const $ = cheerio.load(renderComponent('table', EXAMPLE_TABLE));
729
+
730
+ expect($('.ons-figure')[0].tagName).toBe('div');
731
+ });
732
+
733
+ it('passes `title` to the figure component', () => {
734
+ const faker = templateFaker();
735
+ const figureSpy = faker.spy('figure');
736
+
737
+ faker.renderComponent('table', {
738
+ ...EXAMPLE_TABLE,
739
+ title: 'Population by region',
740
+ });
741
+
742
+ expect(figureSpy.occurrences[0].title).toBe('Population by region');
743
+ });
744
+
745
+ it('passes `subtitle` to the figure component', () => {
746
+ const faker = templateFaker();
747
+ const figureSpy = faker.spy('figure');
748
+
749
+ faker.renderComponent('table', {
750
+ ...EXAMPLE_TABLE,
751
+ subtitle: 'Mid-year estimates, 2023',
752
+ });
753
+
754
+ expect(figureSpy.occurrences[0].subtitle).toBe('Mid-year estimates, 2023');
755
+ });
756
+
757
+ it('passes `headingLevel` to the figure component', () => {
758
+ const faker = templateFaker();
759
+ const figureSpy = faker.spy('figure');
760
+
761
+ faker.renderComponent('table', {
762
+ ...EXAMPLE_TABLE,
763
+ headingLevel: 3,
764
+ });
765
+
766
+ expect(figureSpy.occurrences[0].headingLevel).toBe(3);
767
+ });
768
+
769
+ it('passes `figureNumber` to the figure component', () => {
770
+ const faker = templateFaker();
771
+ const figureSpy = faker.spy('figure');
772
+
773
+ faker.renderComponent('table', {
774
+ ...EXAMPLE_TABLE,
775
+ figureNumber: 'Table 1',
776
+ });
777
+
778
+ expect(figureSpy.occurrences[0].figureNumber).toBe('Table 1');
779
+ });
780
+
781
+ it('passes `footnotes` to the figure component', () => {
782
+ const faker = templateFaker();
783
+ const figureSpy = faker.spy('figure');
784
+
785
+ const footnotes = {
786
+ title: 'Footnotes',
787
+ content: 'Data is seasonally adjusted.',
788
+ };
789
+
790
+ faker.renderComponent('table', {
791
+ ...EXAMPLE_TABLE,
792
+ footnotes,
793
+ });
794
+
795
+ expect(figureSpy.occurrences[0].footnotes).toEqual(footnotes);
796
+ });
797
+
798
+ it('passes `download` to the figure component', () => {
799
+ const faker = templateFaker();
800
+ const figureSpy = faker.spy('figure');
801
+
802
+ const download = {
803
+ title: 'Download this table',
804
+ itemsList: [
805
+ {
806
+ text: 'Table data (CSV, 2KB)',
807
+ url: '/data/table.csv',
808
+ download: 'file',
809
+ },
810
+ ],
811
+ };
812
+
813
+ faker.renderComponent('table', {
814
+ ...EXAMPLE_TABLE,
815
+ download,
816
+ });
817
+
818
+ expect(figureSpy.occurrences[0].download).toEqual(download);
819
+ });
820
+
821
+ it('passes `sourceNote` to the figure component', () => {
822
+ const faker = templateFaker();
823
+ const figureSpy = faker.spy('figure');
824
+
825
+ faker.renderComponent('table', {
826
+ ...EXAMPLE_TABLE,
827
+ sourceNote: 'Source: Office for National Statistics',
828
+ });
829
+
830
+ expect(figureSpy.occurrences[0].caption).toBe('Source: Office for National Statistics');
831
+ });
832
+
833
+ it('sets `useDivForRootElement` on the figure component', () => {
834
+ const faker = templateFaker();
835
+ const figureSpy = faker.spy('figure');
836
+
837
+ faker.renderComponent('table', EXAMPLE_TABLE);
838
+
839
+ expect(figureSpy.occurrences[0].useDivForRootElement).toBe(true);
840
+ });
841
+ });
683
842
  });
@@ -1,7 +1,6 @@
1
1
  .ons-table {
2
2
  border-collapse: collapse;
3
3
  border-spacing: 0;
4
- margin-bottom: 1rem;
5
4
  width: 100%;
6
5
 
7
6
  &__head {
@@ -241,4 +240,10 @@
241
240
  }
242
241
  }
243
242
  }
243
+
244
+ // Used when there is no source note, footnotes or downloads after the table, to match the previous bottom spacing
245
+ // If there source note, footnotes or downloads after the table, the figure component handles the extra spacing
246
+ &--bottom-space {
247
+ margin-bottom: 1rem;
248
+ }
244
249
  }
@@ -0,0 +1,46 @@
1
+ {% from "components/table/_macro.njk" import onsTable %}
2
+ {{
3
+ onsTable({
4
+ "ariaLabel": "Basic table example",
5
+ "id": "basic-table",
6
+ "ths": [
7
+ {
8
+ "value": "Column A"
9
+ },
10
+ {
11
+ "value": "Column B"
12
+ },
13
+ {
14
+ "value": "Column C"
15
+ }
16
+ ],
17
+ "trs": [
18
+ {
19
+ "tds": [
20
+ {
21
+ "value": "Cell A1"
22
+ },
23
+ {
24
+ "value": "Cell B1"
25
+ },
26
+ {
27
+ "value": "Cell C1"
28
+ }
29
+ ]
30
+ },
31
+ {
32
+ "tds": [
33
+ {
34
+ "value": "Cell A2"
35
+ },
36
+ {
37
+ "value": "Cell B2"
38
+ },
39
+ {
40
+ "value": "Cell C2"
41
+ }
42
+ ]
43
+ }
44
+ ]
45
+ })
46
+ }}
@@ -0,0 +1,47 @@
1
+ {% from "components/table/_macro.njk" import onsTable %}
2
+ {{
3
+ onsTable({
4
+ "caption": "A basic table with a visually hidden caption",
5
+ "hideCaption": true,
6
+ "id": "basic-table",
7
+ "ths": [
8
+ {
9
+ "value": "Column A"
10
+ },
11
+ {
12
+ "value": "Column B"
13
+ },
14
+ {
15
+ "value": "Column C"
16
+ }
17
+ ],
18
+ "trs": [
19
+ {
20
+ "tds": [
21
+ {
22
+ "value": "Cell A1"
23
+ },
24
+ {
25
+ "value": "Cell B1"
26
+ },
27
+ {
28
+ "value": "Cell C1"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "tds": [
34
+ {
35
+ "value": "Cell A2"
36
+ },
37
+ {
38
+ "value": "Cell B2"
39
+ },
40
+ {
41
+ "value": "Cell C2"
42
+ }
43
+ ]
44
+ }
45
+ ]
46
+ })
47
+ }}