govuk_publishing_components 35.15.5 → 35.16.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/govuk_publishing_components_manifest.js +1 -0
  3. data/app/assets/images/option-select/input-icon.svg +3 -0
  4. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js +19 -1
  5. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/pii-remover.js +1 -1
  6. data/app/assets/javascripts/govuk_publishing_components/components/option-select.js +312 -0
  7. data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
  8. data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +26 -0
  9. data/app/assets/stylesheets/govuk_publishing_components/components/_option-select.scss +172 -0
  10. data/app/views/govuk_publishing_components/components/_image_card.html.erb +8 -2
  11. data/app/views/govuk_publishing_components/components/_option_select.html.erb +71 -0
  12. data/app/views/govuk_publishing_components/components/docs/image_card.yml +13 -0
  13. data/app/views/govuk_publishing_components/components/docs/option_select.yml +343 -0
  14. data/config/locales/ar.yml +4 -0
  15. data/config/locales/az.yml +4 -0
  16. data/config/locales/be.yml +4 -0
  17. data/config/locales/bg.yml +4 -0
  18. data/config/locales/bn.yml +4 -0
  19. data/config/locales/cs.yml +4 -0
  20. data/config/locales/cy.yml +4 -0
  21. data/config/locales/da.yml +4 -0
  22. data/config/locales/de.yml +4 -0
  23. data/config/locales/dr.yml +4 -0
  24. data/config/locales/el.yml +4 -0
  25. data/config/locales/en.yml +4 -0
  26. data/config/locales/es-419.yml +4 -0
  27. data/config/locales/es.yml +4 -0
  28. data/config/locales/et.yml +4 -0
  29. data/config/locales/fa.yml +4 -0
  30. data/config/locales/fi.yml +4 -0
  31. data/config/locales/fr.yml +4 -0
  32. data/config/locales/gd.yml +4 -0
  33. data/config/locales/gu.yml +4 -0
  34. data/config/locales/he.yml +4 -0
  35. data/config/locales/hi.yml +4 -0
  36. data/config/locales/hr.yml +4 -0
  37. data/config/locales/hu.yml +4 -0
  38. data/config/locales/hy.yml +4 -0
  39. data/config/locales/id.yml +4 -0
  40. data/config/locales/is.yml +4 -0
  41. data/config/locales/it.yml +4 -0
  42. data/config/locales/ja.yml +4 -0
  43. data/config/locales/ka.yml +4 -0
  44. data/config/locales/kk.yml +4 -0
  45. data/config/locales/ko.yml +4 -0
  46. data/config/locales/lt.yml +4 -0
  47. data/config/locales/lv.yml +4 -0
  48. data/config/locales/ms.yml +4 -0
  49. data/config/locales/mt.yml +4 -0
  50. data/config/locales/nl.yml +4 -0
  51. data/config/locales/no.yml +4 -0
  52. data/config/locales/pa-pk.yml +4 -0
  53. data/config/locales/pa.yml +4 -0
  54. data/config/locales/pl.yml +4 -0
  55. data/config/locales/ps.yml +4 -0
  56. data/config/locales/pt.yml +4 -0
  57. data/config/locales/ro.yml +4 -0
  58. data/config/locales/ru.yml +4 -0
  59. data/config/locales/si.yml +4 -0
  60. data/config/locales/sk.yml +4 -0
  61. data/config/locales/sl.yml +4 -0
  62. data/config/locales/so.yml +4 -0
  63. data/config/locales/sq.yml +4 -0
  64. data/config/locales/sr.yml +4 -0
  65. data/config/locales/sv.yml +4 -0
  66. data/config/locales/sw.yml +4 -0
  67. data/config/locales/ta.yml +4 -0
  68. data/config/locales/th.yml +4 -0
  69. data/config/locales/tk.yml +4 -0
  70. data/config/locales/tr.yml +4 -0
  71. data/config/locales/uk.yml +4 -0
  72. data/config/locales/ur.yml +4 -0
  73. data/config/locales/uz.yml +4 -0
  74. data/config/locales/vi.yml +4 -0
  75. data/config/locales/zh-hk.yml +4 -0
  76. data/config/locales/zh-tw.yml +4 -0
  77. data/config/locales/zh.yml +4 -0
  78. data/lib/govuk_publishing_components/presenters/image_card_helper.rb +6 -2
  79. data/lib/govuk_publishing_components/version.rb +1 -1
  80. data/node_modules/axe-core/axe.js +6 -6
  81. data/node_modules/axe-core/axe.min.js +2 -2
  82. data/node_modules/axe-core/locales/_template.json +4 -4
  83. data/node_modules/axe-core/package.json +1 -1
  84. data/node_modules/axe-core/sri-history.json +4 -0
  85. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3117de6a0b4a66caea24d67e4c462c728ef09fdc3cd3503ca0e2429673726631
4
- data.tar.gz: 164a43d2a5ccc732f37fbdf6eb862fc500311f473b9cf1aca998515d6c978c14
3
+ metadata.gz: d631949b7bdb6aa90aff397986118f929cbae4071ef96b3a623c123c6496224d
4
+ data.tar.gz: ef75a103619c27bc964664673a17475579132d0b909e254fce0afcc6316256d9
5
5
  SHA512:
6
- metadata.gz: f9e56a63dc6f33e2df012aa4993cdd9404d07d8c96ecfe39ffe253676aa443deabadc47062b4a9443ee8e2f0fa89943629dd145b8e673f9c1ddef6e56fb5624d
7
- data.tar.gz: ca4f944dbcbf4d77171f797bc1f3b16caad24b513dbb2c49d0749edba6570f9acb701922cd0fa4d33259ec2b80ebbabd5ad8e9390bfa2fb0e54aa58e5eab14d5
6
+ metadata.gz: '01786b90a26218b6b5dff054852d4e67a77f36d307029ff6fd03f8b15cd005e9264f8719a03f78f05dc776f284c24c972eb6101940e8afd41a44a696c3b404f5'
7
+ data.tar.gz: 775eb1304962e2349b3e19c8ce7acfb92dc927443a7a01253692909c174f6b5e196129d40104f773794b2ac8e1674e0c65361e605808910f01163b9d69ad5f6a
@@ -60,6 +60,7 @@
60
60
  //= link govuk_publishing_components/components/_metadata.css
61
61
  //= link govuk_publishing_components/components/_modal-dialogue.css
62
62
  //= link govuk_publishing_components/components/_notice.css
63
+ //= link govuk_publishing_components/components/_option-select.css
63
64
  //= link govuk_publishing_components/components/_organisation-logo.css
64
65
  //= link govuk_publishing_components/components/_panel.css
65
66
  //= link govuk_publishing_components/components/_phase-banner.css
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="40" height="40">
2
+ <path d="M25.7 24.8L21.9 21c.7-1 1.1-2.2 1.1-3.5 0-3.6-2.9-6.5-6.5-6.5S10 13.9 10 17.5s2.9 6.5 6.5 6.5c1.6 0 3-.6 4.1-1.5l3.7 3.7 1.4-1.4zM12 17.5c0-2.5 2-4.5 4.5-4.5s4.5 2 4.5 4.5-2 4.5-4.5 4.5-4.5-2-4.5-4.5z" fill="currentColor" />
3
+ </svg>
@@ -59,7 +59,8 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
59
59
  devolved_nations_banner: this.getElementAttribute('data-ga4-devolved-nations-banner') || undefined,
60
60
  cookie_banner: document.querySelector('[data-ga4-cookie-banner]') ? 'true' : undefined,
61
61
  intervention: this.getInterventionPresence(),
62
- query_string: this.getQueryString()
62
+ query_string: this.getQueryString(),
63
+ search_term: this.getSearchTerm()
63
64
  }
64
65
  }
65
66
  window.GOVUK.analyticsGa4.core.sendData(data)
@@ -74,6 +75,23 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
74
75
  return window.location.search
75
76
  },
76
77
 
78
+ getSearchTerm: function () {
79
+ var queryString = this.getSearch()
80
+
81
+ if (!queryString) {
82
+ return undefined
83
+ }
84
+
85
+ var searchTerm = queryString.match(/keywords=([^&]*)/)
86
+ if (!searchTerm) {
87
+ return undefined
88
+ }
89
+
90
+ searchTerm = searchTerm[0].replace('keywords=', '')
91
+ searchTerm = this.PIIRemover.stripPIIWithOverride(searchTerm, true, true)
92
+ return searchTerm
93
+ },
94
+
77
95
  getQueryString: function () {
78
96
  var queryString = this.getSearch()
79
97
  if (queryString) {
@@ -2,7 +2,7 @@
2
2
  'use strict'
3
3
 
4
4
  var GOVUK = global.GOVUK || {}
5
- var EMAIL_PATTERN = /[^\s=/?&#]+(?:@|%40)[^\s=/?&]+/g
5
+ var EMAIL_PATTERN = /[^\s=/?&#+]+(?:@|%40)[^\s=/?&+]+/g
6
6
  var POSTCODE_PATTERN = /\b[A-PR-UWYZ][A-HJ-Z]?[0-9][0-9A-HJKMNPR-Y]?(?:[\s+]|%20)*[0-9](?!refund)[ABD-HJLNPQ-Z]{2,3}\b/gi
7
7
  var DATE_PATTERN_NUMERIC = /\d{4}(-?)\d{2}(-?)\d{2}/g
8
8
  var DATE_PATTERN_STRING = /\d{1,2}\s(January|February|March|April|May|June|July|August|September|October|November|December)\s\d{4}/g
@@ -0,0 +1,312 @@
1
+ window.GOVUK = window.GOVUK || {}
2
+ window.GOVUK.Modules = window.GOVUK.Modules || {};
3
+
4
+ (function (Modules) {
5
+ /* This JavaScript provides two functional enhancements to option-select components:
6
+ 1) A count that shows how many results have been checked in the option-container
7
+ 2) Open/closing of the list of checkboxes
8
+ */
9
+ function OptionSelect ($module) {
10
+ this.$optionSelect = $module
11
+ this.$options = this.$optionSelect.querySelectorAll("input[type='checkbox']")
12
+ this.$optionsContainer = this.$optionSelect.querySelector('.js-options-container')
13
+ this.$optionList = this.$optionsContainer.querySelector('.js-auto-height-inner')
14
+ this.$allCheckboxes = this.$optionsContainer.querySelectorAll('.govuk-checkboxes__item')
15
+ this.hasFilter = this.$optionSelect.getAttribute('data-filter-element') || ''
16
+
17
+ this.checkedCheckboxes = []
18
+
19
+ this.mq = window.matchMedia('(min-width: 641px)')
20
+ this.isClosedOnLoad = this.$optionSelect.getAttribute('data-closed-on-load')
21
+ this.isClosedOnLoadMobile = this.$optionSelect.getAttribute('data-closed-on-load-mobile')
22
+ }
23
+
24
+ OptionSelect.prototype.init = function () {
25
+ if (this.hasFilter.length) {
26
+ var filterEl = document.createElement('div')
27
+ filterEl.innerHTML = this.hasFilter
28
+
29
+ var optionSelectFilter = document.createElement('div')
30
+ optionSelectFilter.classList.add('gem-c-option-select__filter')
31
+ optionSelectFilter.innerHTML = filterEl.childNodes[0].nodeValue
32
+
33
+ this.$optionsContainer.parentNode.insertBefore(optionSelectFilter, this.$optionsContainer)
34
+
35
+ this.$filter = this.$optionSelect.querySelector('input[name="option-select-filter"]')
36
+ this.$filterCount = document.getElementById(this.$filter.getAttribute('aria-describedby'))
37
+ this.filterTextSingle = ' ' + this.$filterCount.getAttribute('data-single')
38
+ this.filterTextMultiple = ' ' + this.$filterCount.getAttribute('data-multiple')
39
+ this.filterTextSelected = ' ' + this.$filterCount.getAttribute('data-selected')
40
+ this.checkboxLabels = []
41
+ this.filterTimeout = 0
42
+
43
+ this.getAllCheckedCheckboxes()
44
+ for (var i = 0; i < this.$allCheckboxes.length; i++) {
45
+ this.checkboxLabels.push(this.cleanString(this.$allCheckboxes[i].textContent))
46
+ }
47
+
48
+ this.$filter.addEventListener('keyup', this.typeFilterText.bind(this))
49
+ }
50
+
51
+ // Attach listener to update checked count
52
+ this.$optionsContainer.querySelector('.gem-c-checkboxes__list').addEventListener('change', this.updateCheckedCount.bind(this))
53
+
54
+ // Replace div.container-head with a button
55
+ this.replaceHeadingSpanWithButton()
56
+
57
+ // Add js-collapsible class to parent for CSS
58
+ this.$optionSelect.classList.add('js-collapsible')
59
+
60
+ // Add open/close listeners
61
+ var button = this.$optionSelect.querySelector('.js-container-button')
62
+ button.addEventListener('click', this.toggleOptionSelect.bind(this))
63
+
64
+ // Toggle option visibility depending on screen size (min-width: 641px) and
65
+ // presence of any 'closed' properties (`data-closed-on-load`, `data-closed-on-load-mobile`).
66
+ // See https://github.com/alphagov/govuk-frontend/blob/main/packages/govuk-frontend/src/govuk/settings/_media-queries.scss#L10-L14
67
+ if (this.mq.matches) {
68
+ this.toggleVisibility(true)
69
+ } else {
70
+ this.toggleVisibility(false)
71
+ }
72
+
73
+ var checkedString = this.checkedString()
74
+ if (checkedString) {
75
+ this.attachCheckedCounter(checkedString)
76
+ }
77
+ }
78
+
79
+ OptionSelect.prototype.toggleVisibility = function (isTabletOrLarger) {
80
+ if (isTabletOrLarger) {
81
+ if (this.isClosedOnLoad === 'true') {
82
+ this.close()
83
+ } else {
84
+ this.setupHeight()
85
+ }
86
+ } else {
87
+ if (this.isClosedOnLoadMobile === 'true' || this.isClosedOnLoad === 'true') {
88
+ this.close()
89
+ } else {
90
+ this.setContainerHeight(201)
91
+ }
92
+ }
93
+ }
94
+
95
+ OptionSelect.prototype.typeFilterText = function (event) {
96
+ event.stopPropagation()
97
+ var ENTER_KEY = 13
98
+
99
+ if (event.keyCode !== ENTER_KEY) {
100
+ clearTimeout(this.filterTimeout)
101
+ this.filterTimeout = setTimeout(
102
+ function () { this.doFilter(this) }.bind(this),
103
+ 300
104
+ )
105
+ } else {
106
+ event.preventDefault() // prevents finder forms from being submitted when user presses ENTER
107
+ }
108
+ }
109
+
110
+ OptionSelect.prototype.cleanString = function cleanString (text) {
111
+ text = text.replace(/&/g, 'and')
112
+ text = text.replace(/[’',:–-]/g, '') // remove punctuation characters
113
+ text = text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // escape special characters
114
+ return text.trim().replace(/\s\s+/g, ' ').toLowerCase() // replace multiple spaces with one
115
+ }
116
+
117
+ OptionSelect.prototype.getAllCheckedCheckboxes = function getAllCheckedCheckboxes () {
118
+ this.checkedCheckboxes = []
119
+
120
+ for (var i = 0; i < this.$options.length; i++) {
121
+ if (this.$options[i].checked) {
122
+ this.checkedCheckboxes.push(i)
123
+ }
124
+ }
125
+ }
126
+
127
+ OptionSelect.prototype.doFilter = function doFilter (obj) {
128
+ var filterBy = obj.cleanString(obj.$filter.value)
129
+ var showCheckboxes = obj.checkedCheckboxes.slice()
130
+ var i = 0
131
+
132
+ for (i = 0; i < obj.$allCheckboxes.length; i++) {
133
+ if (showCheckboxes.indexOf(i) === -1 && obj.checkboxLabels[i].search(filterBy) !== -1) {
134
+ showCheckboxes.push(i)
135
+ }
136
+ }
137
+
138
+ for (i = 0; i < obj.$allCheckboxes.length; i++) {
139
+ obj.$allCheckboxes[i].style.display = 'none'
140
+ }
141
+
142
+ for (i = 0; i < showCheckboxes.length; i++) {
143
+ obj.$allCheckboxes[showCheckboxes[i]].style.display = 'block'
144
+ }
145
+
146
+ var lenChecked = obj.$optionsContainer.querySelectorAll('.govuk-checkboxes__input:checked').length
147
+ var len = showCheckboxes.length + lenChecked
148
+ var html = len + (len === 1 ? obj.filterTextSingle : obj.filterTextMultiple) + ', ' + lenChecked + obj.filterTextSelected
149
+ obj.$filterCount.innerHTML = html
150
+ }
151
+
152
+ OptionSelect.prototype.replaceHeadingSpanWithButton = function replaceHeadingSpanWithButton () {
153
+ /* Replace the span within the heading with a button element. This is based on feedback from Léonie Watson.
154
+ * The button has all of the accessibility hooks that are used by screen readers and etc.
155
+ * We do this in the JavaScript because if the JavaScript is not active then the button shouldn't
156
+ * be there as there is no JS to handle the click event.
157
+ */
158
+ var containerHead = this.$optionSelect.querySelector('.js-container-button')
159
+ var jsContainerHeadHTML = containerHead.innerHTML
160
+
161
+ // Create button and replace the preexisting html with the button.
162
+ var button = document.createElement('button')
163
+ button.setAttribute('class', 'js-container-button gem-c-option-select__title gem-c-option-select__button')
164
+ // Add type button to override default type submit when this component is used within a form
165
+ button.setAttribute('type', 'button')
166
+ button.setAttribute('aria-expanded', true)
167
+ button.setAttribute('id', containerHead.getAttribute('id'))
168
+ button.setAttribute('aria-controls', this.$optionsContainer.getAttribute('id'))
169
+ button.innerHTML = jsContainerHeadHTML
170
+ containerHead.parentNode.replaceChild(button, containerHead)
171
+
172
+ // GA4 Accordion tracking. Relies on the ga4-finder-tracker setting the index first, so we wrap this in a custom event.
173
+ window.addEventListener('ga4-filter-indexes-added', function () {
174
+ if (window.GOVUK.analyticsGa4) {
175
+ if (window.GOVUK.analyticsGa4.Ga4FinderTracker) {
176
+ window.GOVUK.analyticsGa4.Ga4FinderTracker.addFilterButtonTracking(button, button.innerHTML)
177
+ }
178
+ }
179
+ })
180
+ }
181
+
182
+ OptionSelect.prototype.attachCheckedCounter = function attachCheckedCounter (checkedString) {
183
+ var element = document.createElement('div')
184
+ element.setAttribute('class', 'gem-c-option-select__selected-counter js-selected-counter')
185
+ element.innerHTML = checkedString
186
+ this.$optionSelect.querySelector('.js-container-button').insertAdjacentElement('afterend', element)
187
+ }
188
+
189
+ OptionSelect.prototype.updateCheckedCount = function updateCheckedCount () {
190
+ var checkedString = this.checkedString()
191
+ var checkedStringElement = this.$optionSelect.querySelector('.js-selected-counter')
192
+
193
+ if (checkedString) {
194
+ if (checkedStringElement === null) {
195
+ this.attachCheckedCounter(checkedString)
196
+ } else {
197
+ checkedStringElement.textContent = checkedString
198
+ }
199
+ } else if (checkedStringElement) {
200
+ checkedStringElement.parentNode.removeChild(checkedStringElement)
201
+ }
202
+ }
203
+
204
+ OptionSelect.prototype.checkedString = function checkedString () {
205
+ this.getAllCheckedCheckboxes()
206
+ var count = this.checkedCheckboxes.length
207
+ var checkedString = false
208
+ if (count > 0) {
209
+ checkedString = count + ' selected'
210
+ }
211
+
212
+ return checkedString
213
+ }
214
+
215
+ OptionSelect.prototype.toggleOptionSelect = function toggleOptionSelect (e) {
216
+ if (this.isClosed()) {
217
+ this.open()
218
+ } else {
219
+ this.close()
220
+ }
221
+ e.preventDefault()
222
+ }
223
+
224
+ OptionSelect.prototype.open = function open () {
225
+ if (this.isClosed()) {
226
+ this.$optionSelect.querySelector('.js-container-button').setAttribute('aria-expanded', true)
227
+ this.$optionSelect.classList.remove('js-closed')
228
+ this.$optionSelect.classList.add('js-opened')
229
+ if (!this.$optionsContainer.style.height) {
230
+ this.setupHeight()
231
+ }
232
+ }
233
+ }
234
+
235
+ OptionSelect.prototype.close = function close () {
236
+ this.$optionSelect.classList.remove('js-opened')
237
+ this.$optionSelect.classList.add('js-closed')
238
+ this.$optionSelect.querySelector('.js-container-button').setAttribute('aria-expanded', false)
239
+ }
240
+
241
+ OptionSelect.prototype.isClosed = function isClosed () {
242
+ return this.$optionSelect.classList.contains('js-closed')
243
+ }
244
+
245
+ OptionSelect.prototype.setContainerHeight = function setContainerHeight (height) {
246
+ this.$optionsContainer.style.height = height + 'px'
247
+ }
248
+
249
+ OptionSelect.prototype.isCheckboxVisible = function isCheckboxVisible (option) {
250
+ var initialOptionContainerHeight = this.$optionsContainer.clientHeight
251
+ var optionListOffsetTop = this.$optionList.getBoundingClientRect().top
252
+ var distanceFromTopOfContainer = option.getBoundingClientRect().top - optionListOffsetTop
253
+ return distanceFromTopOfContainer < initialOptionContainerHeight
254
+ }
255
+
256
+ OptionSelect.prototype.getVisibleCheckboxes = function getVisibleCheckboxes () {
257
+ var visibleCheckboxes = []
258
+ for (var i = 0; i < this.$options.length; i++) {
259
+ if (this.isCheckboxVisible(this.$options[i])) {
260
+ visibleCheckboxes.push(this.$options[i])
261
+ }
262
+ }
263
+
264
+ // add an extra checkbox, if the label of the first is too long it collapses onto itself
265
+ if (this.$options[visibleCheckboxes.length]) {
266
+ visibleCheckboxes.push(this.$options[visibleCheckboxes.length])
267
+ }
268
+ return visibleCheckboxes
269
+ }
270
+
271
+ OptionSelect.prototype.isFacetsContainerHidden = function isFacetsContainerHidden () {
272
+ var facetsContent = this.$optionSelect.parentElement
273
+ var isFacetsContentHidden = false
274
+ // check whether this is hidden by progressive disclosure,
275
+ // because height calculations won't work
276
+ // would use offsetParent === null but for IE10+
277
+ if (facetsContent) {
278
+ isFacetsContentHidden = !(facetsContent.offsetWidth || facetsContent.offsetHeight || facetsContent.getClientRects().length)
279
+ }
280
+
281
+ return isFacetsContentHidden
282
+ }
283
+
284
+ OptionSelect.prototype.setupHeight = function setupHeight () {
285
+ var initialOptionContainerHeight = this.$optionsContainer.clientHeight
286
+ var height = this.$optionList.offsetHeight
287
+
288
+ var isFacetsContainerHidden = this.isFacetsContainerHidden()
289
+
290
+ if (isFacetsContainerHidden) {
291
+ initialOptionContainerHeight = 200
292
+ height = 200
293
+ }
294
+
295
+ // Resize if the list is only slightly bigger than its container
296
+ // If isFacetsContainerHidden is true, then 200 < 250
297
+ // And the container height is always set to 201px
298
+ if (height < initialOptionContainerHeight + 50) {
299
+ this.setContainerHeight(height + 1)
300
+ return
301
+ }
302
+
303
+ // Resize to cut last item cleanly in half
304
+ var visibleCheckboxes = this.getVisibleCheckboxes()
305
+
306
+ var lastVisibleCheckbox = visibleCheckboxes[visibleCheckboxes.length - 1]
307
+ var position = lastVisibleCheckbox.parentNode.offsetTop // parent element is relative
308
+ this.setContainerHeight(position + (lastVisibleCheckbox.clientHeight / 1.5))
309
+ }
310
+
311
+ Modules.OptionSelect = OptionSelect
312
+ })(window.GOVUK.Modules)
@@ -57,6 +57,7 @@ $govuk-new-link-styles: true;
57
57
  @import "components/metadata";
58
58
  @import "components/modal-dialogue";
59
59
  @import "components/notice";
60
+ @import "components/option-select";
60
61
  @import "components/organisation-logo";
61
62
  @import "components/panel";
62
63
  @import "components/phase-banner";
@@ -41,6 +41,13 @@
41
41
  }
42
42
  }
43
43
 
44
+ @include govuk-media-query($from: tablet) {
45
+ .gem-c-image-card.gem-c-image-card--two-thirds {
46
+ margin: 0 (- govuk-spacing(3)) govuk-spacing(6) (- govuk-spacing(3));
47
+ display: block;
48
+ }
49
+ }
50
+
44
51
  @include govuk-media-query($from: mobile, $until: tablet) {
45
52
  .gem-c-image-card {
46
53
  margin: 0 (- govuk-spacing(3)) govuk-spacing(6) (- govuk-spacing(3));
@@ -53,6 +60,25 @@
53
60
  .gem-c-image-card__text-wrapper {
54
61
  @include govuk-grid-column($width: one-half, $at: mobile);
55
62
  }
63
+
64
+ .gem-c-image-card__image-wrapper.gem-c-image-card__image-wrapper--one-third {
65
+ @include govuk-grid-column($width: one-third, $float: right, $at: mobile);
66
+ }
67
+
68
+ .gem-c-image-card__text-wrapper.gem-c-image-card__text-wrapper--two-thirds {
69
+ @include govuk-grid-column($width: two-thirds, $float: right, $at: mobile);
70
+ }
71
+ }
72
+
73
+ @include govuk-media-query($from: tablet) {
74
+ .gem-c-image-card__image-wrapper.gem-c-image-card__image-wrapper--one-third {
75
+ @include govuk-grid-column($width: one-third, $float: right, $at: tablet);
76
+ }
77
+
78
+ .gem-c-image-card__text-wrapper.gem-c-image-card__text-wrapper--two-thirds {
79
+ @include govuk-grid-column($width: two-thirds, $float: right, $at: tablet);
80
+ padding-left: 0;
81
+ }
56
82
  }
57
83
 
58
84
  .gem-c-image-card__image {
@@ -0,0 +1,172 @@
1
+ @import "govuk_publishing_components/individual_component_support";
2
+
3
+ .gem-c-option-select {
4
+ position: relative;
5
+ padding: 0 0 govuk-spacing(2);
6
+ margin-bottom: govuk-spacing(2);
7
+ border-bottom: 1px solid $govuk-border-colour;
8
+
9
+ @include govuk-media-query($from: desktop) {
10
+ // Redefine scrollbars on desktop where these lists are scrollable
11
+ // so they are always visible in option lists
12
+ ::-webkit-scrollbar {
13
+ -webkit-appearance: none;
14
+ width: 7px;
15
+ }
16
+
17
+ ::-webkit-scrollbar-thumb {
18
+ border-radius: 4px;
19
+
20
+ background-color: rgba(0, 0, 0, .5);
21
+ -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, .87);
22
+ }
23
+ }
24
+
25
+ .gem-c-checkboxes {
26
+ margin: 0;
27
+ }
28
+ }
29
+
30
+ .gem-c-option-select__title {
31
+ @include govuk-font(19);
32
+ margin: 0;
33
+ }
34
+
35
+ .gem-c-option-select__button {
36
+ z-index: 1;
37
+ background: none;
38
+ border: 0;
39
+ text-align: left;
40
+ padding: 0;
41
+ cursor: pointer;
42
+ color: $govuk-link-colour;
43
+
44
+ &:hover {
45
+ text-decoration: underline;
46
+ text-underline-offset: .1em;
47
+ @include govuk-link-hover-decoration;
48
+ }
49
+
50
+ &::-moz-focus-inner {
51
+ border: 0;
52
+ }
53
+
54
+ &:focus {
55
+ outline: none;
56
+ text-decoration: none;
57
+ @include govuk-focused-text;
58
+ }
59
+
60
+ &[disabled] {
61
+ background-image: none;
62
+ color: inherit;
63
+ }
64
+
65
+ // Extend the touch area of the button to span the heading
66
+ &:after {
67
+ content: "";
68
+ position: absolute;
69
+ top: 0;
70
+ right: 0;
71
+ bottom: 0;
72
+ left: 0;
73
+ z-index: 2;
74
+ }
75
+ }
76
+
77
+ .gem-c-option-select__icon {
78
+ display: none;
79
+ position: absolute;
80
+ top: 0;
81
+ left: 9px;
82
+ width: 30px;
83
+ height: 40px;
84
+ fill: govuk-colour("black");
85
+ }
86
+
87
+ .gem-c-option-select__container {
88
+ position: relative;
89
+ max-height: 200px;
90
+ overflow-y: auto;
91
+ overflow-x: hidden;
92
+ background-color: govuk-colour("white");
93
+
94
+ &:focus {
95
+ outline: 0;
96
+ }
97
+ }
98
+
99
+ .gem-c-option-select__container--large {
100
+ max-height: 600px;
101
+ }
102
+
103
+ .gem-c-option-select__container-inner {
104
+ padding: govuk-spacing(1) 13px;
105
+ }
106
+
107
+ .gem-c-option-select__filter {
108
+ position: relative;
109
+ background: govuk-colour("white");
110
+ padding: 13px 13px govuk-spacing(2) 13px;
111
+ }
112
+
113
+ .gem-c-option-select__filter-input {
114
+ @include govuk-font(19);
115
+ background: image-url("option-select/input-icon.svg") govuk-colour("white") no-repeat -5px -3px;
116
+
117
+ @include govuk-media-query($from: tablet) {
118
+ @include govuk-font(16);
119
+ }
120
+ }
121
+
122
+ .gem-c-option-select__filter-input.govuk-input {
123
+ padding-left: 33px;
124
+ }
125
+
126
+ .js-enabled {
127
+ .gem-c-option-select__heading {
128
+ position: relative;
129
+ padding: 10px 8px 5px 43px;
130
+ margin: 0;
131
+ }
132
+
133
+ [aria-expanded="true"] ~ .gem-c-option-select__icon--up {
134
+ display: block;
135
+ }
136
+
137
+ [aria-expanded="false"] ~ .gem-c-option-select__icon--down {
138
+ display: block;
139
+ }
140
+
141
+ .gem-c-option-select__container {
142
+ height: 200px;
143
+ }
144
+
145
+ .gem-c-option-select__container--large {
146
+ height: 600px;
147
+ }
148
+
149
+ [data-closed-on-load="true"] .gem-c-option-select__container {
150
+ display: none;
151
+ }
152
+ }
153
+
154
+ .gem-c-option-select__selected-counter {
155
+ @include govuk-font($size: 14);
156
+ color: $govuk-text-colour;
157
+ margin-top: 3px;
158
+ }
159
+
160
+ .gem-c-option-select.js-closed {
161
+ .gem-c-option-select__filter,
162
+ .gem-c-option-select__container {
163
+ display: none;
164
+ }
165
+ }
166
+
167
+ .gem-c-option-select.js-opened {
168
+ .gem-c-option-select__filter,
169
+ .gem-c-option-select__container {
170
+ display: block;
171
+ }
172
+ }
@@ -7,11 +7,17 @@
7
7
  brand_helper = GovukPublishingComponents::AppHelpers::BrandHelper.new(brand)
8
8
  card_helper = GovukPublishingComponents::Presenters::ImageCardHelper.new(local_assigns, brand_helper)
9
9
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
10
+
10
11
  classes = %w[gem-c-image-card]
12
+ classes << "govuk-grid-row" if card_helper.two_thirds
11
13
  classes << "gem-c-image-card--large" if card_helper.large
14
+ classes << "gem-c-image-card--two-thirds" if card_helper.two_thirds
12
15
  classes << "gem-c-image-card--no-image" unless (card_helper.image_src || card_helper.youtube_video_id)
13
16
  classes << brand_helper.brand_class if brand_helper.brand_class
14
17
 
18
+ text_wrapper_classes = %w[gem-c-image-card__text-wrapper]
19
+ text_wrapper_classes << "gem-c-image-card__text-wrapper--two-thirds" if card_helper.two_thirds
20
+
15
21
  font_size ||= card_helper.large ? 'm' : 's'
16
22
  heading_class = %w[gem-c-image-card__title]
17
23
  heading_class << shared_helper.get_heading_size(font_size, 's')
@@ -33,7 +39,7 @@
33
39
  %>
34
40
  <% if card_helper.href || card_helper.extra_details.any? %>
35
41
  <%= content_tag(:div, class: classes, "data-module": data_modules, lang: card_helper.lang) do %>
36
- <div class="gem-c-image-card__text-wrapper">
42
+ <%= content_tag(:div, class: text_wrapper_classes) do %>
37
43
  <div class="gem-c-image-card__header-and-context-wrapper">
38
44
  <% if card_helper.heading_text %>
39
45
  <%= content_tag(shared_helper.get_heading_level, class: heading_class) do %>
@@ -69,7 +75,7 @@
69
75
  <% if card_helper.metadata %>
70
76
  <p class="gem-c-image-card__metadata"><%= card_helper.metadata %></p>
71
77
  <% end %>
72
- </div>
78
+ <% end %>
73
79
  <%= card_helper.media %>
74
80
  <% end %>
75
81
  <% end %>