govuk_publishing_components 32.0.0 → 33.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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/component_guide/accessibility-test.js +0 -1
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +175 -0
  4. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-ecommerce-tracker.js +1 -1
  5. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-event-tracker.js +5 -13
  6. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +80 -309
  7. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js +2 -2
  8. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-specialist-link-tracker.js +140 -0
  9. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +3 -0
  10. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4.js +1 -0
  11. data/app/assets/javascripts/govuk_publishing_components/components/accordion.js +12 -1
  12. data/app/assets/javascripts/govuk_publishing_components/components/layout-super-navigation-header.js +13 -4
  13. data/app/assets/javascripts/govuk_publishing_components/components/single-page-notification-button.js +24 -8
  14. data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-reporter.js +83 -86
  15. data/app/assets/stylesheets/govuk_publishing_components/components/_big-number.scss +2 -5
  16. data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +1 -5
  17. data/app/assets/stylesheets/govuk_publishing_components/components/_input.scss +3 -5
  18. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +10 -30
  19. data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +0 -7
  20. data/app/assets/stylesheets/govuk_publishing_components/components/_share-links.scss +0 -6
  21. data/app/views/govuk_publishing_components/components/_accordion.html.erb +14 -1
  22. data/app/views/govuk_publishing_components/components/_error_summary.html.erb +27 -26
  23. data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +2 -2
  24. data/app/views/govuk_publishing_components/components/_phase_banner.html.erb +1 -1
  25. data/app/views/govuk_publishing_components/components/_share_links.html.erb +18 -15
  26. data/app/views/govuk_publishing_components/components/_single_page_notification_button.html.erb +1 -1
  27. data/app/views/govuk_publishing_components/components/docs/accordion.yml +15 -3
  28. data/app/views/govuk_publishing_components/components/docs/button.yml +10 -0
  29. data/app/views/govuk_publishing_components/components/docs/share_links.yml +59 -30
  30. data/app/views/govuk_publishing_components/components/docs/single_page_notification_button.yml +10 -1
  31. data/app/views/govuk_publishing_components/components/feedback/_yes_no_banner.html.erb +3 -3
  32. data/config/locales/ar.yml +4 -1
  33. data/config/locales/az.yml +4 -1
  34. data/config/locales/be.yml +4 -1
  35. data/config/locales/bg.yml +4 -1
  36. data/config/locales/bn.yml +4 -1
  37. data/config/locales/cs.yml +4 -1
  38. data/config/locales/cy.yml +4 -1
  39. data/config/locales/da.yml +4 -1
  40. data/config/locales/de.yml +4 -1
  41. data/config/locales/dr.yml +4 -1
  42. data/config/locales/el.yml +4 -1
  43. data/config/locales/en.yml +20 -17
  44. data/config/locales/es-419.yml +4 -1
  45. data/config/locales/es.yml +4 -1
  46. data/config/locales/et.yml +4 -1
  47. data/config/locales/fa.yml +4 -1
  48. data/config/locales/fi.yml +4 -1
  49. data/config/locales/fr.yml +4 -1
  50. data/config/locales/gd.yml +4 -1
  51. data/config/locales/gu.yml +4 -1
  52. data/config/locales/he.yml +4 -1
  53. data/config/locales/hi.yml +4 -1
  54. data/config/locales/hr.yml +4 -1
  55. data/config/locales/hu.yml +4 -1
  56. data/config/locales/hy.yml +4 -1
  57. data/config/locales/id.yml +4 -1
  58. data/config/locales/is.yml +4 -1
  59. data/config/locales/it.yml +4 -1
  60. data/config/locales/ja.yml +4 -1
  61. data/config/locales/ka.yml +4 -1
  62. data/config/locales/kk.yml +4 -1
  63. data/config/locales/ko.yml +4 -1
  64. data/config/locales/lt.yml +4 -1
  65. data/config/locales/lv.yml +4 -1
  66. data/config/locales/ms.yml +4 -1
  67. data/config/locales/mt.yml +4 -1
  68. data/config/locales/nl.yml +4 -1
  69. data/config/locales/no.yml +4 -1
  70. data/config/locales/pa-pk.yml +4 -1
  71. data/config/locales/pa.yml +4 -1
  72. data/config/locales/pl.yml +4 -1
  73. data/config/locales/ps.yml +4 -1
  74. data/config/locales/pt.yml +4 -1
  75. data/config/locales/ro.yml +4 -1
  76. data/config/locales/ru.yml +4 -1
  77. data/config/locales/si.yml +4 -1
  78. data/config/locales/sk.yml +4 -1
  79. data/config/locales/sl.yml +4 -1
  80. data/config/locales/so.yml +4 -1
  81. data/config/locales/sq.yml +4 -1
  82. data/config/locales/sr.yml +4 -1
  83. data/config/locales/sv.yml +4 -1
  84. data/config/locales/sw.yml +4 -1
  85. data/config/locales/ta.yml +4 -1
  86. data/config/locales/th.yml +4 -1
  87. data/config/locales/tk.yml +4 -1
  88. data/config/locales/tr.yml +4 -1
  89. data/config/locales/uk.yml +4 -1
  90. data/config/locales/ur.yml +4 -1
  91. data/config/locales/uz.yml +4 -1
  92. data/config/locales/vi.yml +4 -1
  93. data/config/locales/zh-hk.yml +4 -1
  94. data/config/locales/zh-tw.yml +4 -1
  95. data/config/locales/zh.yml +4 -1
  96. data/lib/govuk_publishing_components/presenters/button_helper.rb +7 -1
  97. data/lib/govuk_publishing_components/presenters/single_page_notification_button_helper.rb +25 -1
  98. data/lib/govuk_publishing_components/version.rb +1 -1
  99. data/node_modules/axe-core/axe.js +4567 -4678
  100. data/node_modules/axe-core/axe.min.js +2 -2
  101. data/node_modules/axe-core/package.json +2 -2
  102. data/node_modules/axe-core/sri-history.json +8 -0
  103. data/node_modules/govuk-frontend/README.md +1 -2
  104. data/node_modules/govuk-frontend/govuk/all.js +1398 -273
  105. data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +70 -0
  106. data/node_modules/govuk-frontend/govuk/common/index.js +172 -0
  107. data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +373 -0
  108. data/node_modules/govuk-frontend/govuk/common.js +138 -3
  109. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +753 -25
  110. data/node_modules/govuk-frontend/govuk/components/accordion/fixtures.json +54 -22
  111. data/node_modules/govuk-frontend/govuk/components/accordion/macro-options.json +36 -0
  112. data/node_modules/govuk-frontend/govuk/components/accordion/template.njk +7 -1
  113. data/node_modules/govuk-frontend/govuk/components/back-link/fixtures.json +12 -12
  114. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/fixtures.json +22 -22
  115. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +23 -5
  116. data/node_modules/govuk-frontend/govuk/components/button/button.js +365 -107
  117. data/node_modules/govuk-frontend/govuk/components/button/fixtures.json +85 -66
  118. data/node_modules/govuk-frontend/govuk/components/button/template.njk +1 -1
  119. data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +9 -0
  120. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +1033 -121
  121. data/node_modules/govuk-frontend/govuk/components/character-count/fixtures.json +112 -36
  122. data/node_modules/govuk-frontend/govuk/components/character-count/macro-options.json +42 -0
  123. data/node_modules/govuk-frontend/govuk/components/character-count/template.njk +27 -3
  124. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +30 -2
  125. data/node_modules/govuk-frontend/govuk/components/checkboxes/fixtures.json +96 -93
  126. data/node_modules/govuk-frontend/govuk/components/cookie-banner/fixtures.json +46 -46
  127. data/node_modules/govuk-frontend/govuk/components/date-input/fixtures.json +50 -50
  128. data/node_modules/govuk-frontend/govuk/components/details/details.js +43 -13
  129. data/node_modules/govuk-frontend/govuk/components/details/fixtures.json +20 -20
  130. data/node_modules/govuk-frontend/govuk/components/error-message/fixtures.json +20 -20
  131. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +268 -6
  132. data/node_modules/govuk-frontend/govuk/components/error-summary/fixtures.json +44 -35
  133. data/node_modules/govuk-frontend/govuk/components/error-summary/template.njk +25 -21
  134. data/node_modules/govuk-frontend/govuk/components/fieldset/fixtures.json +51 -39
  135. data/node_modules/govuk-frontend/govuk/components/file-upload/fixtures.json +26 -26
  136. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +1 -1
  137. data/node_modules/govuk-frontend/govuk/components/footer/fixtures.json +46 -46
  138. data/node_modules/govuk-frontend/govuk/components/footer/macro-options.json +2 -2
  139. data/node_modules/govuk-frontend/govuk/components/header/fixtures.json +93 -38
  140. data/node_modules/govuk-frontend/govuk/components/header/header.js +6 -0
  141. data/node_modules/govuk-frontend/govuk/components/header/macro-options.json +8 -2
  142. data/node_modules/govuk-frontend/govuk/components/header/template.njk +4 -2
  143. data/node_modules/govuk-frontend/govuk/components/hint/fixtures.json +12 -12
  144. data/node_modules/govuk-frontend/govuk/components/input/fixtures.json +80 -80
  145. data/node_modules/govuk-frontend/govuk/components/inset-text/fixtures.json +12 -12
  146. data/node_modules/govuk-frontend/govuk/components/label/fixtures.json +34 -34
  147. data/node_modules/govuk-frontend/govuk/components/notification-banner/fixtures.json +56 -46
  148. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +252 -2
  149. data/node_modules/govuk-frontend/govuk/components/notification-banner/template.njk +1 -1
  150. data/node_modules/govuk-frontend/govuk/components/pagination/_index.scss +10 -7
  151. data/node_modules/govuk-frontend/govuk/components/pagination/fixtures.json +33 -26
  152. data/node_modules/govuk-frontend/govuk/components/panel/fixtures.json +18 -18
  153. data/node_modules/govuk-frontend/govuk/components/phase-banner/fixtures.json +14 -14
  154. data/node_modules/govuk-frontend/govuk/components/radios/fixtures.json +94 -91
  155. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +30 -2
  156. data/node_modules/govuk-frontend/govuk/components/select/fixtures.json +32 -32
  157. data/node_modules/govuk-frontend/govuk/components/skip-link/fixtures.json +22 -20
  158. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +10 -4
  159. data/node_modules/govuk-frontend/govuk/components/summary-list/fixtures.json +50 -50
  160. data/node_modules/govuk-frontend/govuk/components/table/_index.scss +1 -1
  161. data/node_modules/govuk-frontend/govuk/components/table/fixtures.json +40 -40
  162. data/node_modules/govuk-frontend/govuk/components/tabs/fixtures.json +29 -29
  163. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +28 -0
  164. data/node_modules/govuk-frontend/govuk/components/tag/fixtures.json +28 -28
  165. data/node_modules/govuk-frontend/govuk/components/textarea/fixtures.json +34 -34
  166. data/node_modules/govuk-frontend/govuk/components/warning-text/fixtures.json +14 -14
  167. data/node_modules/govuk-frontend/govuk/core/_section-break.scss +1 -1
  168. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +2 -2
  169. data/node_modules/govuk-frontend/govuk/helpers/_links.scss +6 -6
  170. data/node_modules/govuk-frontend/govuk/i18n.js +390 -0
  171. data/node_modules/govuk-frontend/govuk/macros/i18n.njk +15 -0
  172. data/node_modules/govuk-frontend/govuk/settings/_all.scss +1 -0
  173. data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +12 -0
  174. data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +26 -0
  175. data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +23 -0
  176. data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +12 -0
  177. data/node_modules/govuk-frontend/govuk/settings/_warnings.scss +53 -0
  178. data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +20 -6
  179. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +21 -0
  180. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +300 -0
  181. data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +21 -0
  182. data/node_modules/govuk-frontend/govuk-esm/all.mjs +50 -27
  183. data/node_modules/govuk-frontend/govuk-esm/common/closest-attribute-value.mjs +15 -0
  184. data/node_modules/govuk-frontend/govuk-esm/common/index.mjs +159 -0
  185. data/node_modules/govuk-frontend/govuk-esm/common/normalise-dataset.mjs +58 -0
  186. data/node_modules/govuk-frontend/govuk-esm/common.mjs +6 -28
  187. data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +113 -43
  188. data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +67 -30
  189. data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +325 -123
  190. data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +9 -3
  191. data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +22 -8
  192. data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +48 -6
  193. data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +6 -0
  194. data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +32 -2
  195. data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +9 -3
  196. data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +10 -4
  197. data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +8 -2
  198. data/node_modules/govuk-frontend/govuk-esm/i18n.mjs +380 -0
  199. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Date/now.mjs +13 -0
  200. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/dataset.mjs +68 -0
  201. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/String/prototype/trim.mjs +13 -0
  202. data/node_modules/govuk-frontend/govuk-prototype-kit/init.js +7 -0
  203. data/node_modules/govuk-frontend/govuk-prototype-kit/init.scss +12 -0
  204. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +138 -7
  205. data/node_modules/govuk-frontend/package.json +1 -1
  206. metadata +22 -3
@@ -0,0 +1,58 @@
1
+ import '../vendor/polyfills/Element/prototype/dataset.mjs'
2
+ import '../vendor/polyfills/String/prototype/trim.mjs'
3
+
4
+ /**
5
+ * Normalise string
6
+ *
7
+ * 'If it looks like a duck, and it quacks like a duck…' 🦆
8
+ *
9
+ * If the passed value looks like a boolean or a number, convert it to a boolean
10
+ * or number.
11
+ *
12
+ * Designed to be used to convert config passed via data attributes (which are
13
+ * always strings) into something sensible.
14
+ *
15
+ * @param {string} value - The value to normalise
16
+ * @returns {string | boolean | number | undefined} Normalised data
17
+ */
18
+ export function normaliseString (value) {
19
+ if (typeof value !== 'string') {
20
+ return value
21
+ }
22
+
23
+ var trimmedValue = value.trim()
24
+
25
+ if (trimmedValue === 'true') {
26
+ return true
27
+ }
28
+
29
+ if (trimmedValue === 'false') {
30
+ return false
31
+ }
32
+
33
+ // Empty / whitespace-only strings are considered finite so we need to check
34
+ // the length of the trimmed string as well
35
+ if (trimmedValue.length > 0 && isFinite(trimmedValue)) {
36
+ return Number(trimmedValue)
37
+ }
38
+
39
+ return value
40
+ }
41
+
42
+ /**
43
+ * Normalise dataset
44
+ *
45
+ * Loop over an object and normalise each value using normaliseData function
46
+ *
47
+ * @param {DOMStringMap} dataset - HTML element dataset
48
+ * @returns {Object<string, string | boolean | number | undefined>} Normalised dataset
49
+ */
50
+ export function normaliseDataset (dataset) {
51
+ var out = {}
52
+
53
+ for (var key in dataset) {
54
+ out[key] = normaliseString(dataset[key])
55
+ }
56
+
57
+ return out
58
+ }
@@ -1,28 +1,6 @@
1
- /**
2
- * TODO: Ideally this would be a NodeList.prototype.forEach polyfill
3
- * This seems to fail in IE8, requires more investigation.
4
- * See: https://github.com/imagitama/nodelist-foreach-polyfill
5
- */
6
- export function nodeListForEach (nodes, callback) {
7
- if (window.NodeList.prototype.forEach) {
8
- return nodes.forEach(callback)
9
- }
10
- for (var i = 0; i < nodes.length; i++) {
11
- callback.call(window, nodes[i], i, nodes)
12
- }
13
- }
14
-
15
- // Used to generate a unique string, allows multiple instances of the component without
16
- // Them conflicting with each other.
17
- // https://stackoverflow.com/a/8809472
18
- export function generateUniqueID () {
19
- var d = new Date().getTime()
20
- if (typeof window.performance !== 'undefined' && typeof window.performance.now === 'function') {
21
- d += window.performance.now() // use high-precision timer if available
22
- }
23
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
24
- var r = (d + Math.random() * 16) % 16 | 0
25
- d = Math.floor(d / 16)
26
- return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
27
- })
28
- }
1
+ // Implementation of common function is gathered in the `common` folder
2
+ // as some are split in their own modules to limit impacts of the polyfills
3
+ // they require.
4
+ // This module exports the non polyfilled methods as they used to be
5
+ // to avoid breaking changes
6
+ export * from './common/index.mjs'
@@ -1,31 +1,56 @@
1
-
2
- /*
3
- Accordion
4
-
5
- This allows a collection of sections to be collapsed by default,
6
- showing only their headers. Sections can be expanded or collapsed
7
- individually by clicking their headers. An "Show all sections" button is
8
- also added to the top of the accordion, which switches to "Hide all sections"
9
- when all the sections are expanded.
10
-
11
- The state of each section is saved to the DOM via the `aria-expanded`
12
- attribute, which also provides accessibility.
13
-
14
- A Chevron icon has been added for extra affordance that this is an interactive element.
15
-
16
- */
17
-
18
- import { nodeListForEach } from '../../common.mjs'
1
+ import { nodeListForEach, mergeConfigs, extractConfigByNamespace } from '../../common/index.mjs'
2
+ import { I18n } from '../../i18n.mjs'
19
3
  import '../../vendor/polyfills/Function/prototype/bind.mjs'
20
4
  import '../../vendor/polyfills/Element/prototype/classList.mjs'
5
+ import '../../vendor/polyfills/String/prototype/trim.mjs'
6
+ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
21
7
 
22
- function Accordion ($module) {
8
+ /**
9
+ * @constant
10
+ * @type {AccordionTranslations}
11
+ * @see Default value for {@link AccordionConfig.i18n}
12
+ * @default
13
+ */
14
+ var ACCORDION_TRANSLATIONS = {
15
+ hideAllSections: 'Hide all sections',
16
+ hideSection: 'Hide',
17
+ hideSectionAriaLabel: 'Hide this section',
18
+ showAllSections: 'Show all sections',
19
+ showSection: 'Show',
20
+ showSectionAriaLabel: 'Show this section'
21
+ }
22
+
23
+ /**
24
+ * Accordion component
25
+ *
26
+ * This allows a collection of sections to be collapsed by default, showing only
27
+ * their headers. Sections can be expanded or collapsed individually by clicking
28
+ * their headers. A "Show all sections" button is also added to the top of the
29
+ * accordion, which switches to "Hide all sections" when all the sections are
30
+ * expanded.
31
+ *
32
+ * The state of each section is saved to the DOM via the `aria-expanded`
33
+ * attribute, which also provides accessibility.
34
+ *
35
+ * @class
36
+ * @param {HTMLElement} $module - HTML element to use for accordion
37
+ * @param {AccordionConfig} [config] - Accordion config
38
+ */
39
+ function Accordion ($module, config) {
23
40
  this.$module = $module
24
- this.moduleId = $module.getAttribute('id')
25
41
  this.$sections = $module.querySelectorAll('.govuk-accordion__section')
26
- this.$showAllButton = ''
27
42
  this.browserSupportsSessionStorage = helper.checkForSessionStorage()
28
43
 
44
+ var defaultConfig = {
45
+ i18n: ACCORDION_TRANSLATIONS
46
+ }
47
+ this.config = mergeConfigs(
48
+ defaultConfig,
49
+ config || {},
50
+ normaliseDataset($module.dataset)
51
+ )
52
+ this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'))
53
+
29
54
  this.controlsClass = 'govuk-accordion__controls'
30
55
  this.showAllClass = 'govuk-accordion__show-all'
31
56
  this.showAllTextClass = 'govuk-accordion__show-all-text'
@@ -116,7 +141,7 @@ Accordion.prototype.constructHeaderMarkup = function ($headerWrapper, index) {
116
141
  // Create a button element that will replace the '.govuk-accordion__section-button' span
117
142
  var $button = document.createElement('button')
118
143
  $button.setAttribute('type', 'button')
119
- $button.setAttribute('aria-controls', this.moduleId + '-content-' + (index + 1))
144
+ $button.setAttribute('aria-controls', this.$module.id + '-content-' + (index + 1))
120
145
 
121
146
  // Copy all attributes (https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes) from $span to $button
122
147
  for (var i = 0; i < $span.attributes.length; i++) {
@@ -233,17 +258,34 @@ Accordion.prototype.setExpanded = function (expanded, $section) {
233
258
  var $icon = $section.querySelector('.' + this.upChevronIconClass)
234
259
  var $showHideText = $section.querySelector('.' + this.sectionShowHideTextClass)
235
260
  var $button = $section.querySelector('.' + this.sectionButtonClass)
236
- var newButtonText = expanded ? 'Hide' : 'Show'
237
-
238
- // Build additional copy of "this section" for assistive technology and place inside toggle link
239
- var $visuallyHiddenText = document.createElement('span')
240
- $visuallyHiddenText.classList.add('govuk-visually-hidden')
241
- $visuallyHiddenText.innerHTML = ' this section'
261
+ var newButtonText = expanded
262
+ ? this.i18n.t('hideSection')
263
+ : this.i18n.t('showSection')
242
264
 
243
- $showHideText.innerHTML = newButtonText
244
- $showHideText.appendChild($visuallyHiddenText)
265
+ $showHideText.innerText = newButtonText
245
266
  $button.setAttribute('aria-expanded', expanded)
246
267
 
268
+ // Update aria-label combining
269
+ var $header = $section.querySelector('.' + this.sectionHeadingTextClass)
270
+ var ariaLabelParts = [$header.innerText.trim()]
271
+
272
+ var $summary = $section.querySelector('.' + this.sectionSummaryClass)
273
+ if ($summary) {
274
+ ariaLabelParts.push($summary.innerText.trim())
275
+ }
276
+
277
+ var ariaLabelMessage = expanded
278
+ ? this.i18n.t('hideSectionAriaLabel')
279
+ : this.i18n.t('showSectionAriaLabel')
280
+ ariaLabelParts.push(ariaLabelMessage)
281
+
282
+ /*
283
+ * Join with a comma to add pause for assistive technology.
284
+ * Example: [heading]Section A ,[pause] Show this section.
285
+ * https://accessibility.blog.gov.uk/2017/12/18/what-working-on-gov-uk-navigation-taught-us-about-accessibility/
286
+ */
287
+ $button.setAttribute('aria-label', ariaLabelParts.join(' , '))
288
+
247
289
  // Swap icon, change class
248
290
  if (expanded) {
249
291
  $section.classList.add(this.sectionExpandedClass)
@@ -278,9 +320,11 @@ Accordion.prototype.checkIfAllSectionsOpen = function () {
278
320
  Accordion.prototype.updateShowAllButton = function (expanded) {
279
321
  var $showAllIcon = this.$showAllButton.querySelector('.' + this.upChevronIconClass)
280
322
  var $showAllText = this.$showAllButton.querySelector('.' + this.showAllTextClass)
281
- var newButtonText = expanded ? 'Hide all sections' : 'Show all sections'
323
+ var newButtonText = expanded
324
+ ? this.i18n.t('hideAllSections')
325
+ : this.i18n.t('showAllSections')
282
326
  this.$showAllButton.setAttribute('aria-expanded', expanded)
283
- $showAllText.innerHTML = newButtonText
327
+ $showAllText.innerText = newButtonText
284
328
 
285
329
  // Swap icon, toggle class
286
330
  if (expanded) {
@@ -343,17 +387,14 @@ Accordion.prototype.setInitialState = function ($section) {
343
387
  }
344
388
 
345
389
  /**
346
- * Create an element to improve semantics of the section button with punctuation
347
- * @return {object} DOM element
348
- *
349
- * Used to add pause (with a comma) for assistive technology.
350
- * Example: [heading]Section A ,[pause] Show this section.
351
- * https://accessibility.blog.gov.uk/2017/12/18/what-working-on-gov-uk-navigation-taught-us-about-accessibility/
352
- *
353
- * Adding punctuation to the button can also improve its general semantics by dividing its contents
354
- * into thematic chunks.
355
- * See https://github.com/alphagov/govuk-frontend/issues/2327#issuecomment-922957442
356
- */
390
+ * Create an element to improve semantics of the section button with punctuation
391
+ *
392
+ * @returns {HTMLSpanElement} DOM element
393
+ *
394
+ * Adding punctuation to the button can also improve its general semantics by dividing its contents
395
+ * into thematic chunks.
396
+ * See https://github.com/alphagov/govuk-frontend/issues/2327#issuecomment-922957442
397
+ */
357
398
  Accordion.prototype.getButtonPunctuationEl = function () {
358
399
  var $punctuationEl = document.createElement('span')
359
400
  $punctuationEl.classList.add('govuk-visually-hidden', 'govuk-accordion__section-heading-divider')
@@ -362,3 +403,32 @@ Accordion.prototype.getButtonPunctuationEl = function () {
362
403
  }
363
404
 
364
405
  export default Accordion
406
+
407
+ /**
408
+ * Accordion config
409
+ *
410
+ * @typedef {object} AccordionConfig
411
+ * @property {AccordionTranslations} [i18n = ACCORDION_TRANSLATIONS] - See constant {@link ACCORDION_TRANSLATIONS}
412
+ */
413
+
414
+ /**
415
+ * Accordion translations
416
+ *
417
+ * @typedef {object} AccordionTranslations
418
+ *
419
+ * Messages used by the component for the labels of its buttons. This includes
420
+ * the visible text shown on screen, and text to help assistive technology users
421
+ * for the buttons toggling each section.
422
+ * @property {string} [hideAllSections] - The text content for the 'Hide all
423
+ * sections' button, used when at least one section is expanded.
424
+ * @property {string} [hideSection] - The text content for the 'Hide'
425
+ * button, used when a section is expanded.
426
+ * @property {string} [hideSectionAriaLabel] - The text content appended to the
427
+ * 'Hide' button's accessible name when a section is expanded.
428
+ * @property {string} [showAllSections] - The text content for the 'Show all
429
+ * sections' button, used when all sections are collapsed.
430
+ * @property {string} [showSection] - The text content for the 'Show'
431
+ * button, used when a section is collapsed.
432
+ * @property {string} [showSectionAriaLabel] - The text content appended to the
433
+ * 'Show' button's accessible name when a section is expanded.
434
+ */
@@ -1,47 +1,84 @@
1
+ import { mergeConfigs } from '../../common/index.mjs'
2
+ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
1
3
  import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normaliziation
2
4
  import '../../vendor/polyfills/Function/prototype/bind.mjs'
3
5
 
4
6
  var KEY_SPACE = 32
5
7
  var DEBOUNCE_TIMEOUT_IN_SECONDS = 1
6
8
 
7
- function Button ($module) {
9
+ /**
10
+ * JavaScript enhancements for the Button component
11
+ *
12
+ * @class
13
+ * @param {HTMLElement} $module - The element this component controls
14
+ * @param {ButtonConfig} config - Button config
15
+ */
16
+ function Button ($module, config) {
17
+ if (!$module) {
18
+ return this
19
+ }
20
+
8
21
  this.$module = $module
9
22
  this.debounceFormSubmitTimer = null
23
+
24
+ var defaultConfig = {
25
+ preventDoubleClick: false
26
+ }
27
+ this.config = mergeConfigs(
28
+ defaultConfig,
29
+ config || {},
30
+ normaliseDataset($module.dataset)
31
+ )
10
32
  }
11
33
 
12
34
  /**
13
- * JavaScript 'shim' to trigger the click event of element(s) when the space key is pressed.
14
- *
15
- * Created since some Assistive Technologies (for example some Screenreaders)
16
- * will tell a user to press space on a 'button', so this functionality needs to be shimmed
17
- * See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270
18
- *
19
- * @param {object} event event
20
- */
35
+ * Initialise component
36
+ */
37
+ Button.prototype.init = function () {
38
+ if (!this.$module) {
39
+ return
40
+ }
41
+
42
+ this.$module.addEventListener('keydown', this.handleKeyDown)
43
+ this.$module.addEventListener('click', this.debounce.bind(this))
44
+ }
45
+
46
+ /**
47
+ * Trigger a click event when the space key is pressed
48
+ *
49
+ * Some screen readers tell users they can activate things with the 'button'
50
+ * role, so we need to match the functionality of native HTML buttons
51
+ *
52
+ * See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270
53
+ *
54
+ * @param {KeyboardEvent} event
55
+ */
21
56
  Button.prototype.handleKeyDown = function (event) {
22
- // get the target element
23
57
  var target = event.target
24
- // if the element has a role='button' and the pressed key is a space, we'll simulate a click
58
+
25
59
  if (target.getAttribute('role') === 'button' && event.keyCode === KEY_SPACE) {
26
- event.preventDefault()
27
- // trigger the target's click event
60
+ event.preventDefault() // prevent the page from scrolling
28
61
  target.click()
29
62
  }
30
63
  }
31
64
 
32
65
  /**
33
- * If the click quickly succeeds a previous click then nothing will happen.
34
- * This stops people accidentally causing multiple form submissions by
35
- * double clicking buttons.
36
- */
66
+ * Debounce double-clicks
67
+ *
68
+ * If the click quickly succeeds a previous click then nothing will happen. This
69
+ * stops people accidentally causing multiple form submissions by double
70
+ * clicking buttons.
71
+ *
72
+ * @param {MouseEvent} event
73
+ * @returns {undefined | false} - Returns undefined, or false when debounced
74
+ */
37
75
  Button.prototype.debounce = function (event) {
38
- var target = event.target
39
- // Check the button that is clicked on has the preventDoubleClick feature enabled
40
- if (target.getAttribute('data-prevent-double-click') !== 'true') {
76
+ // Check the button that was clicked has preventDoubleClick enabled
77
+ if (!this.config.preventDoubleClick) {
41
78
  return
42
79
  }
43
80
 
44
- // If the timer is still running then we want to prevent the click from submitting the form
81
+ // If the timer is still running, prevent the click from submitting the form
45
82
  if (this.debounceFormSubmitTimer) {
46
83
  event.preventDefault()
47
84
  return false
@@ -52,13 +89,13 @@ Button.prototype.debounce = function (event) {
52
89
  }.bind(this), DEBOUNCE_TIMEOUT_IN_SECONDS * 1000)
53
90
  }
54
91
 
55
- /**
56
- * Initialise an event listener for keydown at document level
57
- * this will help listening for later inserted elements with a role="button"
58
- */
59
- Button.prototype.init = function () {
60
- this.$module.addEventListener('keydown', this.handleKeyDown)
61
- this.$module.addEventListener('click', this.debounce)
62
- }
63
-
64
92
  export default Button
93
+
94
+ /**
95
+ * Button config
96
+ *
97
+ * @typedef {object} ButtonConfig
98
+ * @property {boolean} [preventDoubleClick = false] -
99
+ * Prevent accidental double clicks on submit buttons from submitting forms
100
+ * multiple times.
101
+ */