govuk_publishing_components 34.7.0 → 34.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/lib/govuk_publishing_components/presenters/related_navigation_helper.rb +0 -7
  3. data/lib/govuk_publishing_components/version.rb +1 -1
  4. data/node_modules/govuk-frontend/govuk/all.js +4029 -3792
  5. data/node_modules/govuk-frontend/govuk/all.js.map +1 -0
  6. data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +52 -51
  7. data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js.map +1 -0
  8. data/node_modules/govuk-frontend/govuk/common/index.js +153 -145
  9. data/node_modules/govuk-frontend/govuk/common/index.js.map +1 -0
  10. data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +324 -321
  11. data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js.map +1 -0
  12. data/node_modules/govuk-frontend/govuk/common.js +154 -146
  13. data/node_modules/govuk-frontend/govuk/common.js.map +1 -0
  14. data/node_modules/govuk-frontend/govuk/components/_all.scss +1 -1
  15. data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +23 -4
  16. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +2059 -1654
  17. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js.map +1 -0
  18. data/node_modules/govuk-frontend/govuk/components/accordion/fixtures.json +11 -11
  19. data/node_modules/govuk-frontend/govuk/components/accordion/template.njk +1 -1
  20. data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +19 -19
  21. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +21 -10
  22. data/node_modules/govuk-frontend/govuk/components/button/button.js +927 -917
  23. data/node_modules/govuk-frontend/govuk/components/button/button.js.map +1 -0
  24. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +2050 -2040
  25. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js.map +1 -0
  26. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +1155 -1147
  27. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js.map +1 -0
  28. data/node_modules/govuk-frontend/govuk/components/cookie-banner/fixtures.json +23 -23
  29. data/node_modules/govuk-frontend/govuk/components/cookie-banner/template.njk +1 -1
  30. data/node_modules/govuk-frontend/govuk/components/details/details.js +800 -799
  31. data/node_modules/govuk-frontend/govuk/components/details/details.js.map +1 -0
  32. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +1058 -1045
  33. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js.map +1 -0
  34. data/node_modules/govuk-frontend/govuk/components/header/_index.scss +6 -0
  35. data/node_modules/govuk-frontend/govuk/components/header/header.js +646 -998
  36. data/node_modules/govuk-frontend/govuk/components/header/header.js.map +1 -0
  37. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +760 -752
  38. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js.map +1 -0
  39. data/node_modules/govuk-frontend/govuk/components/pagination/fixtures.json +61 -0
  40. data/node_modules/govuk-frontend/govuk/components/pagination/template.njk +1 -1
  41. data/node_modules/govuk-frontend/govuk/components/phase-banner/macro-options.json +1 -1
  42. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +1110 -1107
  43. data/node_modules/govuk-frontend/govuk/components/radios/radios.js.map +1 -0
  44. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +1017 -1014
  45. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js.map +1 -0
  46. data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +107 -0
  47. data/node_modules/govuk-frontend/govuk/components/summary-list/fixtures.json +318 -23
  48. data/node_modules/govuk-frontend/govuk/components/summary-list/macro-options.json +110 -0
  49. data/node_modules/govuk-frontend/govuk/components/summary-list/template.njk +72 -28
  50. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +1392 -1264
  51. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js.map +1 -0
  52. data/node_modules/govuk-frontend/govuk/i18n.js +363 -364
  53. data/node_modules/govuk-frontend/govuk/i18n.js.map +1 -0
  54. data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +5 -5
  55. data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js +242 -241
  56. data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js.map +1 -0
  57. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +13 -12
  58. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js.map +1 -0
  59. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js +17 -16
  60. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js.map +1 -0
  61. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js +547 -546
  62. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js.map +1 -0
  63. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js +37 -36
  64. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js.map +1 -0
  65. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +251 -250
  66. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js.map +1 -0
  67. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js +21 -20
  68. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js.map +1 -0
  69. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js +198 -197
  70. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js.map +1 -0
  71. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js +198 -197
  72. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js.map +1 -0
  73. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js +106 -105
  74. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js.map +1 -0
  75. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js +400 -399
  76. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js.map +1 -0
  77. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js +239 -238
  78. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js.map +1 -0
  79. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js +72 -71
  80. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js.map +1 -0
  81. data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +14 -13
  82. data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js.map +1 -0
  83. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js +17 -16
  84. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js.map +1 -0
  85. data/node_modules/govuk-frontend/govuk-esm/all.mjs +2 -2
  86. data/node_modules/govuk-frontend/govuk-esm/common/index.mjs +17 -10
  87. data/node_modules/govuk-frontend/govuk-esm/common/normalise-dataset.mjs +3 -1
  88. data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +135 -52
  89. data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +11 -9
  90. data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +10 -7
  91. data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +24 -18
  92. data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +23 -16
  93. data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +15 -11
  94. data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +3 -2
  95. data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +3 -4
  96. data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +10 -9
  97. data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +5 -3
  98. data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +165 -38
  99. data/node_modules/govuk-frontend/govuk-esm/i18n.mjs +9 -11
  100. data/node_modules/govuk-frontend/package.json +1 -1
  101. metadata +34 -2
@@ -1,9 +1,10 @@
1
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
2
- import '../../vendor/polyfills/Event.mjs' // addEventListener
3
- import '../../vendor/polyfills/Element/prototype/closest.mjs'
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
4
2
 
5
3
  import { mergeConfigs } from '../../common/index.mjs'
6
4
  import { normaliseDataset } from '../../common/normalise-dataset.mjs'
5
+ import '../../vendor/polyfills/Element/prototype/closest.mjs'
6
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
7
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
7
8
 
8
9
  /**
9
10
  * JavaScript enhancements for the ErrorSummary
@@ -11,8 +12,8 @@ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
11
12
  * Takes focus on initialisation for accessible announcement, unless disabled in configuration.
12
13
  *
13
14
  * @class
14
- * @param {HTMLElement} $module - The element this component controls
15
- * @param {ErrorSummaryConfig} config - Error summary config
15
+ * @param {HTMLElement} $module - HTML element to use for error summary
16
+ * @param {ErrorSummaryConfig} [config] - Error summary config
16
17
  */
17
18
  function ErrorSummary ($module, config) {
18
19
  // Some consuming code may not be passing a module,
@@ -40,6 +41,9 @@ function ErrorSummary ($module, config) {
40
41
  )
41
42
  }
42
43
 
44
+ /**
45
+ * Initialise component
46
+ */
43
47
  ErrorSummary.prototype.init = function () {
44
48
  var $module = this.$module
45
49
  if (!$module) {
@@ -77,8 +81,8 @@ ErrorSummary.prototype.setFocus = function () {
77
81
  * @param {MouseEvent} event - Click event
78
82
  */
79
83
  ErrorSummary.prototype.handleClick = function (event) {
80
- var target = event.target
81
- if (this.focusTarget(target)) {
84
+ var $target = event.target
85
+ if (this.focusTarget($target)) {
82
86
  event.preventDefault()
83
87
  }
84
88
  }
@@ -98,7 +102,7 @@ ErrorSummary.prototype.handleClick = function (event) {
98
102
  * NVDA (as tested in 2018.3.2) - without this only the field type is announced
99
103
  * (e.g. "Edit, has autocomplete").
100
104
  *
101
- * @param {HTMLElement} $target - Event target
105
+ * @param {EventTarget} $target - Event target
102
106
  * @returns {boolean} True if the target was able to be focussed
103
107
  */
104
108
  ErrorSummary.prototype.focusTarget = function ($target) {
@@ -163,10 +167,10 @@ ErrorSummary.prototype.getAssociatedLegendOrLabel = function ($input) {
163
167
  var $fieldset = $input.closest('fieldset')
164
168
 
165
169
  if ($fieldset) {
166
- var legends = $fieldset.getElementsByTagName('legend')
170
+ var $legends = $fieldset.getElementsByTagName('legend')
167
171
 
168
- if (legends.length) {
169
- var $candidateLegend = legends[0]
172
+ if ($legends.length) {
173
+ var $candidateLegend = $legends[0]
170
174
 
171
175
  // If the input type is radio or checkbox, always use the legend if there
172
176
  // is one.
@@ -1,5 +1,6 @@
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+
1
3
  import '../../vendor/polyfills/Event.mjs'
2
- import '../../vendor/polyfills/Element/prototype/classList.mjs'
3
4
  import '../../vendor/polyfills/Function/prototype/bind.mjs'
4
5
 
5
6
  /**
@@ -28,7 +29,7 @@ function Header ($module) {
28
29
  }
29
30
 
30
31
  /**
31
- * Initialise header
32
+ * Initialise component
32
33
  *
33
34
  * Check for the presence of the header, menu and menu button – if any are
34
35
  * missing then there's nothing to do so return early.
@@ -1,14 +1,13 @@
1
- import '../../vendor/polyfills/Event.mjs' // addEventListener
2
-
3
1
  import { mergeConfigs } from '../../common/index.mjs'
4
2
  import { normaliseDataset } from '../../common/normalise-dataset.mjs'
3
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
5
4
 
6
5
  /**
7
6
  * Notification Banner component
8
7
  *
9
8
  * @class
10
9
  * @param {HTMLElement} $module - HTML element to use for notification banner
11
- * @param {NotificationBannerConfig} config - Notification banner config
10
+ * @param {NotificationBannerConfig} [config] - Notification banner config
12
11
  */
13
12
  function NotificationBanner ($module, config) {
14
13
  this.$module = $module
@@ -24,7 +23,7 @@ function NotificationBanner ($module, config) {
24
23
  }
25
24
 
26
25
  /**
27
- * Initialise the component
26
+ * Initialise component
28
27
  */
29
28
  NotificationBanner.prototype.init = function () {
30
29
  var $module = this.$module
@@ -1,8 +1,9 @@
1
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
2
- // addEventListener, event.target normalization and DOMContentLoaded
3
- import '../../vendor/polyfills/Event.mjs'
4
- import '../../vendor/polyfills/Element/prototype/classList.mjs'
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+
5
3
  import { nodeListForEach } from '../../common/index.mjs'
4
+ import '../../vendor/polyfills/Element/prototype/classList.mjs'
5
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
6
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
6
7
 
7
8
  /**
8
9
  * Radios component
@@ -16,7 +17,7 @@ function Radios ($module) {
16
17
  }
17
18
 
18
19
  /**
19
- * Initialise Radios
20
+ * Initialise component
20
21
  *
21
22
  * Radios can be associated with a 'conditionally revealed' content block – for
22
23
  * example, a radio for 'Phone' could reveal an additional form field for the
@@ -34,17 +35,17 @@ Radios.prototype.init = function () {
34
35
  var $inputs = this.$inputs
35
36
 
36
37
  nodeListForEach($inputs, function ($input) {
37
- var target = $input.getAttribute('data-aria-controls')
38
+ var targetId = $input.getAttribute('data-aria-controls')
38
39
 
39
40
  // Skip radios without data-aria-controls attributes, or where the
40
41
  // target element does not exist.
41
- if (!target || !document.getElementById(target)) {
42
+ if (!targetId || !document.getElementById(targetId)) {
42
43
  return
43
44
  }
44
45
 
45
46
  // Promote the data-aria-controls attribute to a aria-controls attribute
46
47
  // so that the relationship is exposed in the AOM
47
- $input.setAttribute('aria-controls', target)
48
+ $input.setAttribute('aria-controls', targetId)
48
49
  $input.removeAttribute('data-aria-controls')
49
50
  })
50
51
 
@@ -68,7 +69,7 @@ Radios.prototype.init = function () {
68
69
  }
69
70
 
70
71
  /**
71
- * Sync the conditional reveal states for all inputs in this $module.
72
+ * Sync the conditional reveal states for all radio buttons in this $module.
72
73
  */
73
74
  Radios.prototype.syncAllConditionalReveals = function () {
74
75
  nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this))
@@ -1,6 +1,8 @@
1
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+
2
3
  import '../../vendor/polyfills/Element/prototype/classList.mjs'
3
- import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normalization
4
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
5
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
4
6
 
5
7
  /**
6
8
  * Skip link component
@@ -15,7 +17,7 @@ function SkipLink ($module) {
15
17
  }
16
18
 
17
19
  /**
18
- * Initialise the component
20
+ * Initialise component
19
21
  */
20
22
  SkipLink.prototype.init = function () {
21
23
  // Check for module
@@ -1,9 +1,11 @@
1
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+
3
+ import { nodeListForEach } from '../../common/index.mjs'
2
4
  import '../../vendor/polyfills/Element/prototype/classList.mjs'
3
5
  import '../../vendor/polyfills/Element/prototype/nextElementSibling.mjs'
4
6
  import '../../vendor/polyfills/Element/prototype/previousElementSibling.mjs'
5
- import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normaliziation
6
- import { nodeListForEach } from '../../common/index.mjs'
7
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
8
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
7
9
 
8
10
  /**
9
11
  * Tabs component
@@ -19,6 +21,9 @@ function Tabs ($module) {
19
21
  this.jsHiddenClass = 'govuk-tabs__panel--hidden'
20
22
  }
21
23
 
24
+ /**
25
+ * Initialise component
26
+ */
22
27
  Tabs.prototype.init = function () {
23
28
  if (typeof window.matchMedia === 'function') {
24
29
  this.setupResponsiveChecks()
@@ -27,12 +32,18 @@ Tabs.prototype.init = function () {
27
32
  }
28
33
  }
29
34
 
35
+ /**
36
+ * Setup viewport resize check
37
+ */
30
38
  Tabs.prototype.setupResponsiveChecks = function () {
31
39
  this.mql = window.matchMedia('(min-width: 40.0625em)')
32
40
  this.mql.addListener(this.checkMode.bind(this))
33
41
  this.checkMode()
34
42
  }
35
43
 
44
+ /**
45
+ * Setup or teardown handler for viewport resize check
46
+ */
36
47
  Tabs.prototype.checkMode = function () {
37
48
  if (this.mql.matches) {
38
49
  this.setup()
@@ -41,6 +52,9 @@ Tabs.prototype.checkMode = function () {
41
52
  }
42
53
  }
43
54
 
55
+ /**
56
+ * Setup tab component
57
+ */
44
58
  Tabs.prototype.setup = function () {
45
59
  var $module = this.$module
46
60
  var $tabs = this.$tabs
@@ -82,6 +96,9 @@ Tabs.prototype.setup = function () {
82
96
  window.addEventListener('hashchange', $module.boundOnHashChange, true)
83
97
  }
84
98
 
99
+ /**
100
+ * Teardown tab component
101
+ */
85
102
  Tabs.prototype.teardown = function () {
86
103
  var $module = this.$module
87
104
  var $tabs = this.$tabs
@@ -111,7 +128,13 @@ Tabs.prototype.teardown = function () {
111
128
  window.removeEventListener('hashchange', $module.boundOnHashChange, true)
112
129
  }
113
130
 
114
- Tabs.prototype.onHashChange = function (e) {
131
+ /**
132
+ * Handle hashchange event
133
+ *
134
+ * @param {HashChangeEvent} event - Hash change event
135
+ * @returns {void | undefined} Returns void, or undefined when prevented
136
+ */
137
+ Tabs.prototype.onHashChange = function (event) {
115
138
  var hash = window.location.hash
116
139
  var $tabWithHash = this.getTab(hash)
117
140
  if (!$tabWithHash) {
@@ -132,20 +155,41 @@ Tabs.prototype.onHashChange = function (e) {
132
155
  $tabWithHash.focus()
133
156
  }
134
157
 
158
+ /**
159
+ * Hide panel for tab link
160
+ *
161
+ * @param {HTMLAnchorElement} $tab - Tab link
162
+ */
135
163
  Tabs.prototype.hideTab = function ($tab) {
136
164
  this.unhighlightTab($tab)
137
165
  this.hidePanel($tab)
138
166
  }
139
167
 
168
+ /**
169
+ * Show panel for tab link
170
+ *
171
+ * @param {HTMLAnchorElement} $tab - Tab link
172
+ */
140
173
  Tabs.prototype.showTab = function ($tab) {
141
174
  this.highlightTab($tab)
142
175
  this.showPanel($tab)
143
176
  }
144
177
 
178
+ /**
179
+ * Get tab link by hash
180
+ *
181
+ * @param {string} hash - Hash fragment including #
182
+ * @returns {HTMLAnchorElement | null} Tab link
183
+ */
145
184
  Tabs.prototype.getTab = function (hash) {
146
185
  return this.$module.querySelector('.govuk-tabs__tab[href="' + hash + '"]')
147
186
  }
148
187
 
188
+ /**
189
+ * Set tab link and panel attributes
190
+ *
191
+ * @param {HTMLAnchorElement} $tab - Tab link
192
+ */
149
193
  Tabs.prototype.setAttributes = function ($tab) {
150
194
  // set tab attributes
151
195
  var panelId = this.getHref($tab).slice(1)
@@ -162,6 +206,11 @@ Tabs.prototype.setAttributes = function ($tab) {
162
206
  $panel.classList.add(this.jsHiddenClass)
163
207
  }
164
208
 
209
+ /**
210
+ * Unset tab link and panel attributes
211
+ *
212
+ * @param {HTMLAnchorElement} $tab - Tab link
213
+ */
165
214
  Tabs.prototype.unsetAttributes = function ($tab) {
166
215
  // unset tab attributes
167
216
  $tab.removeAttribute('id')
@@ -177,108 +226,186 @@ Tabs.prototype.unsetAttributes = function ($tab) {
177
226
  $panel.classList.remove(this.jsHiddenClass)
178
227
  }
179
228
 
180
- Tabs.prototype.onTabClick = function (e) {
181
- if (!e.target.classList.contains('govuk-tabs__tab')) {
182
- // Allow events on child DOM elements to bubble up to tab parent
229
+ /**
230
+ * Handle tab link clicks
231
+ *
232
+ * @param {MouseEvent} event - Mouse click event
233
+ * @returns {void | false} Returns void, or false within tab link
234
+ */
235
+ Tabs.prototype.onTabClick = function (event) {
236
+ if (!event.target.classList.contains('govuk-tabs__tab')) {
237
+ // Allow events on child DOM elements to bubble up to tab parent
183
238
  return false
184
239
  }
185
- e.preventDefault()
186
- var $newTab = e.target
240
+ event.preventDefault()
241
+ var $newTab = event.target
187
242
  var $currentTab = this.getCurrentTab()
188
243
  this.hideTab($currentTab)
189
244
  this.showTab($newTab)
190
245
  this.createHistoryEntry($newTab)
191
246
  }
192
247
 
248
+ /**
249
+ * Update browser URL hash fragment for tab
250
+ *
251
+ * - Allows back/forward to navigate tabs
252
+ * - Avoids page jump when hash changes
253
+ *
254
+ * @param {HTMLAnchorElement} $tab - Tab link
255
+ */
193
256
  Tabs.prototype.createHistoryEntry = function ($tab) {
194
257
  var $panel = this.getPanel($tab)
195
258
 
196
259
  // Save and restore the id
197
260
  // so the page doesn't jump when a user clicks a tab (which changes the hash)
198
- var id = $panel.id
261
+ var panelId = $panel.id
199
262
  $panel.id = ''
200
263
  this.changingHash = true
201
264
  window.location.hash = this.getHref($tab).slice(1)
202
- $panel.id = id
265
+ $panel.id = panelId
203
266
  }
204
267
 
205
- Tabs.prototype.onTabKeydown = function (e) {
206
- switch (e.keyCode) {
268
+ /**
269
+ * Handle tab keydown event
270
+ *
271
+ * - Press right/down arrow for next tab
272
+ * - Press left/up arrow for previous tab
273
+ *
274
+ * @param {KeyboardEvent} event - Keydown event
275
+ */
276
+ Tabs.prototype.onTabKeydown = function (event) {
277
+ switch (event.keyCode) {
207
278
  case this.keys.left:
208
279
  case this.keys.up:
209
280
  this.activatePreviousTab()
210
- e.preventDefault()
281
+ event.preventDefault()
211
282
  break
212
283
  case this.keys.right:
213
284
  case this.keys.down:
214
285
  this.activateNextTab()
215
- e.preventDefault()
286
+ event.preventDefault()
216
287
  break
217
288
  }
218
289
  }
219
290
 
291
+ /**
292
+ * Activate next tab
293
+ */
220
294
  Tabs.prototype.activateNextTab = function () {
221
- var currentTab = this.getCurrentTab()
222
- var nextTabListItem = currentTab.parentNode.nextElementSibling
223
- if (nextTabListItem) {
224
- var nextTab = nextTabListItem.querySelector('.govuk-tabs__tab')
295
+ var $currentTab = this.getCurrentTab()
296
+ if (!$currentTab) {
297
+ return
225
298
  }
226
- if (nextTab) {
227
- this.hideTab(currentTab)
228
- this.showTab(nextTab)
229
- nextTab.focus()
230
- this.createHistoryEntry(nextTab)
299
+
300
+ var $nextTabListItem = $currentTab.parentElement.nextElementSibling
301
+ if (!$nextTabListItem) {
302
+ return
303
+ }
304
+
305
+ var $nextTab = $nextTabListItem.querySelector('.govuk-tabs__tab')
306
+ if ($nextTab) {
307
+ this.hideTab($currentTab)
308
+ this.showTab($nextTab)
309
+ $nextTab.focus()
310
+ this.createHistoryEntry($nextTab)
231
311
  }
232
312
  }
233
313
 
314
+ /**
315
+ * Activate previous tab
316
+ */
234
317
  Tabs.prototype.activatePreviousTab = function () {
235
- var currentTab = this.getCurrentTab()
236
- var previousTabListItem = currentTab.parentNode.previousElementSibling
237
- if (previousTabListItem) {
238
- var previousTab = previousTabListItem.querySelector('.govuk-tabs__tab')
318
+ var $currentTab = this.getCurrentTab()
319
+ if (!$currentTab) {
320
+ return
321
+ }
322
+
323
+ var $previousTabListItem = $currentTab.parentElement.previousElementSibling
324
+ if (!$previousTabListItem) {
325
+ return
239
326
  }
240
- if (previousTab) {
241
- this.hideTab(currentTab)
242
- this.showTab(previousTab)
243
- previousTab.focus()
244
- this.createHistoryEntry(previousTab)
327
+
328
+ var $previousTab = $previousTabListItem.querySelector('.govuk-tabs__tab')
329
+ if ($previousTab) {
330
+ this.hideTab($currentTab)
331
+ this.showTab($previousTab)
332
+ $previousTab.focus()
333
+ this.createHistoryEntry($previousTab)
245
334
  }
246
335
  }
247
336
 
337
+ /**
338
+ * Get tab panel for tab link
339
+ *
340
+ * @param {HTMLAnchorElement} $tab - Tab link
341
+ * @returns {HTMLDivElement} Tab panel
342
+ */
248
343
  Tabs.prototype.getPanel = function ($tab) {
249
344
  var $panel = this.$module.querySelector(this.getHref($tab))
250
345
  return $panel
251
346
  }
252
347
 
348
+ /**
349
+ * Show tab panel for tab link
350
+ *
351
+ * @param {HTMLAnchorElement} $tab - Tab link
352
+ */
253
353
  Tabs.prototype.showPanel = function ($tab) {
254
354
  var $panel = this.getPanel($tab)
255
355
  $panel.classList.remove(this.jsHiddenClass)
256
356
  }
257
357
 
258
- Tabs.prototype.hidePanel = function (tab) {
259
- var $panel = this.getPanel(tab)
358
+ /**
359
+ * Hide tab panel for tab link
360
+ *
361
+ * @param {HTMLAnchorElement} $tab - Tab link
362
+ */
363
+ Tabs.prototype.hidePanel = function ($tab) {
364
+ var $panel = this.getPanel($tab)
260
365
  $panel.classList.add(this.jsHiddenClass)
261
366
  }
262
367
 
368
+ /**
369
+ * Unset 'selected' state for tab link
370
+ *
371
+ * @param {HTMLAnchorElement} $tab - Tab link
372
+ */
263
373
  Tabs.prototype.unhighlightTab = function ($tab) {
264
374
  $tab.setAttribute('aria-selected', 'false')
265
375
  $tab.parentNode.classList.remove('govuk-tabs__list-item--selected')
266
376
  $tab.setAttribute('tabindex', '-1')
267
377
  }
268
378
 
379
+ /**
380
+ * Set 'selected' state for tab link
381
+ *
382
+ * @param {HTMLAnchorElement} $tab - Tab link
383
+ */
269
384
  Tabs.prototype.highlightTab = function ($tab) {
270
385
  $tab.setAttribute('aria-selected', 'true')
271
386
  $tab.parentNode.classList.add('govuk-tabs__list-item--selected')
272
387
  $tab.setAttribute('tabindex', '0')
273
388
  }
274
389
 
390
+ /**
391
+ * Get current tab link
392
+ *
393
+ * @returns {HTMLAnchorElement | undefined} Tab link
394
+ */
275
395
  Tabs.prototype.getCurrentTab = function () {
276
396
  return this.$module.querySelector('.govuk-tabs__list-item--selected .govuk-tabs__tab')
277
397
  }
278
398
 
279
- // this is because IE doesn't always return the actual value but a relative full path
280
- // should be a utility function most prob
281
- // http://labs.thesedays.com/blog/2010/01/08/getting-the-href-value-with-jquery-in-ie/
399
+ /**
400
+ * Get link hash fragment for href attribute
401
+ *
402
+ * this is because IE doesn't always return the actual value but a relative full path
403
+ * should be a utility function most prob
404
+ * {@link http://labs.thesedays.com/blog/2010/01/08/getting-the-href-value-with-jquery-in-ie/}
405
+ *
406
+ * @param {HTMLAnchorElement} $tab - Tab link
407
+ * @returns {string} Hash fragment including #
408
+ */
282
409
  Tabs.prototype.getHref = function ($tab) {
283
410
  var href = $tab.getAttribute('href')
284
411
  var hash = href.slice(href.indexOf('#'), href.length)
@@ -4,9 +4,9 @@
4
4
  *
5
5
  * @class
6
6
  * @private
7
- * @param {TranslationsFlattened} translations - Key-value pairs of the translation strings to use.
7
+ * @param {Object<string, unknown>} translations - Key-value pairs of the translation strings to use.
8
8
  * @param {object} [config] - Configuration options for the function.
9
- * @param {string} config.locale - An overriding locale for the PluralRules functionality.
9
+ * @param {string} [config.locale] - An overriding locale for the PluralRules functionality.
10
10
  */
11
11
  export function I18n (translations, config) {
12
12
  // Make list of translations available throughout function
@@ -21,8 +21,10 @@ export function I18n (translations, config) {
21
21
  * returns the appropriate string.
22
22
  *
23
23
  * @param {string} lookupKey - The lookup key of the string to use.
24
- * @param {object} options - Any options passed with the translation string, e.g: for string interpolation.
24
+ * @param {Object<string, unknown>} [options] - Any options passed with the translation string, e.g: for string interpolation.
25
25
  * @returns {string} The appropriate translation string.
26
+ * @throws {Error} Lookup key required
27
+ * @throws {Error} Options required for `${}` placeholders
26
28
  */
27
29
  I18n.prototype.t = function (lookupKey, options) {
28
30
  if (!lookupKey) {
@@ -64,7 +66,7 @@ I18n.prototype.t = function (lookupKey, options) {
64
66
  * with the provided data
65
67
  *
66
68
  * @param {string} translationString - The translation string
67
- * @param {object} options - Any options passed with the translation string, e.g: for string interpolation.
69
+ * @param {Object<string, unknown>} options - Any options passed with the translation string, e.g: for string interpolation.
68
70
  * @returns {string} The translation string to output, with ${} placeholders replaced
69
71
  */
70
72
  I18n.prototype.replacePlaceholders = function (translationString, options) {
@@ -137,6 +139,7 @@ I18n.prototype.hasIntlNumberFormatSupport = function () {
137
139
  * @param {string} lookupKey - The lookup key of the string to use.
138
140
  * @param {number} count - Number used to determine which pluralisation to use.
139
141
  * @returns {PluralRule} The suffix associated with the correct pluralisation for this locale.
142
+ * @throws {Error} Plural form `.other` required when preferred plural form is missing
140
143
  */
141
144
  I18n.prototype.getPluralSuffix = function (lookupKey, count) {
142
145
  // Validate that the number is actually a number.
@@ -290,6 +293,7 @@ I18n.pluralRulesMap = {
290
293
  * @type {Object<string, function(number): PluralRule>}
291
294
  */
292
295
  I18n.pluralRules = {
296
+ /* eslint-disable jsdoc/require-jsdoc */
293
297
  arabic: function (n) {
294
298
  if (n === 0) { return 'zero' }
295
299
  if (n === 1) { return 'one' }
@@ -343,6 +347,7 @@ I18n.pluralRules = {
343
347
  if (n === 6) { return 'many' }
344
348
  return 'other'
345
349
  }
350
+ /* eslint-enable jsdoc/require-jsdoc */
346
351
  }
347
352
 
348
353
  /**
@@ -371,10 +376,3 @@ I18n.pluralRules = {
371
376
  * @property {string} [few] - Plural form used for a few
372
377
  * @property {string} [many] - Plural form used for many
373
378
  */
374
-
375
- /**
376
- * Translated messages (flattened)
377
- *
378
- * @private
379
- * @typedef {Object<string, string> | {}} TranslationsFlattened
380
- */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "govuk-frontend",
3
3
  "description": "GOV.UK Frontend contains the code you need to start building a user interface for government platforms and services.",
4
- "version": "4.4.1",
4
+ "version": "4.5.0",
5
5
  "main": "govuk/all.js",
6
6
  "module": "govuk-esm/all.mjs",
7
7
  "exports": {