govuk_tech_docs 2.2.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of govuk_tech_docs might be problematic. Click here for more details.

Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.nvmrc +1 -1
  4. data/.travis.yml +2 -0
  5. data/CHANGELOG.md +26 -1
  6. data/govuk_tech_docs.gemspec +3 -8
  7. data/lib/assets/javascripts/_modules/collapsible-navigation.js +7 -7
  8. data/lib/assets/javascripts/_modules/in-page-navigation.js +2 -4
  9. data/lib/assets/stylesheets/_govuk_tech_docs.scss +9 -10
  10. data/lib/assets/stylesheets/modules/_search.scss +8 -25
  11. data/lib/assets/stylesheets/modules/_technical-documentation.scss +1 -1
  12. data/lib/assets/stylesheets/modules/_toc.scss +11 -11
  13. data/lib/govuk_tech_docs/api_reference/api_reference_extension.rb +0 -1
  14. data/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +70 -186
  15. data/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb +3 -2
  16. data/lib/govuk_tech_docs/api_reference/templates/operation.html.erb +1 -1
  17. data/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb +1 -1
  18. data/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +1 -1
  19. data/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +12 -12
  20. data/lib/govuk_tech_docs/table_of_contents/heading.rb +5 -1
  21. data/lib/govuk_tech_docs/table_of_contents/heading_tree_renderer.rb +2 -2
  22. data/lib/govuk_tech_docs/table_of_contents/helpers.rb +6 -3
  23. data/lib/govuk_tech_docs/tech_docs_html_renderer.rb +1 -1
  24. data/lib/govuk_tech_docs/version.rb +1 -1
  25. data/lib/source/layouts/_header.erb +6 -2
  26. data/lib/source/layouts/_search.erb +1 -1
  27. data/node_modules/govuk-frontend/govuk/_base.scss +3 -0
  28. data/node_modules/govuk-frontend/govuk/all.js +306 -94
  29. data/node_modules/govuk-frontend/govuk/all.scss +1 -3
  30. data/node_modules/govuk-frontend/govuk/components/_all.scss +33 -29
  31. data/node_modules/govuk-frontend/govuk/components/accordion/_accordion.scss +2 -208
  32. data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +197 -0
  33. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +1 -1
  34. data/node_modules/govuk-frontend/govuk/components/back-link/_back-link.scss +2 -65
  35. data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +99 -0
  36. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_breadcrumbs.scss +2 -118
  37. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +138 -0
  38. data/node_modules/govuk-frontend/govuk/components/button/_button.scss +2 -284
  39. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +288 -0
  40. data/node_modules/govuk-frontend/govuk/components/character-count/_character-count.scss +2 -31
  41. data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +25 -0
  42. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +17 -9
  43. data/node_modules/govuk-frontend/govuk/components/checkboxes/_checkboxes.scss +2 -308
  44. data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +320 -0
  45. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +129 -24
  46. data/node_modules/govuk-frontend/govuk/components/cookie-banner/_cookie-banner.scss +2 -0
  47. data/node_modules/govuk-frontend/govuk/components/cookie-banner/_index.scss +51 -0
  48. data/node_modules/govuk-frontend/govuk/components/date-input/_date-input.scss +2 -30
  49. data/node_modules/govuk-frontend/govuk/components/date-input/_index.scss +26 -0
  50. data/node_modules/govuk-frontend/govuk/components/details/_details.scss +2 -88
  51. data/node_modules/govuk-frontend/govuk/components/details/_index.scss +87 -0
  52. data/node_modules/govuk-frontend/govuk/components/error-message/_error-message.scss +2 -15
  53. data/node_modules/govuk-frontend/govuk/components/error-message/_index.scss +11 -0
  54. data/node_modules/govuk-frontend/govuk/components/error-summary/_error-summary.scss +2 -59
  55. data/node_modules/govuk-frontend/govuk/components/error-summary/_index.scss +43 -0
  56. data/node_modules/govuk-frontend/govuk/components/fieldset/_fieldset.scss +2 -68
  57. data/node_modules/govuk-frontend/govuk/components/fieldset/_index.scss +64 -0
  58. data/node_modules/govuk-frontend/govuk/components/file-upload/_file-upload.scss +2 -81
  59. data/node_modules/govuk-frontend/govuk/components/file-upload/_index.scss +49 -0
  60. data/node_modules/govuk-frontend/govuk/components/footer/_footer.scss +2 -244
  61. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +241 -0
  62. data/node_modules/govuk-frontend/govuk/components/header/_header.scss +2 -318
  63. data/node_modules/govuk-frontend/govuk/components/header/_index.scss +331 -0
  64. data/node_modules/govuk-frontend/govuk/components/header/header.js +665 -316
  65. data/node_modules/govuk-frontend/govuk/components/hint/_hint.scss +2 -50
  66. data/node_modules/govuk-frontend/govuk/components/hint/_index.scss +44 -0
  67. data/node_modules/govuk-frontend/govuk/components/input/_index.scss +191 -0
  68. data/node_modules/govuk-frontend/govuk/components/input/_input.scss +2 -103
  69. data/node_modules/govuk-frontend/govuk/components/inset-text/_index.scss +24 -0
  70. data/node_modules/govuk-frontend/govuk/components/inset-text/_inset-text.scss +2 -28
  71. data/node_modules/govuk-frontend/govuk/components/label/_index.scss +41 -0
  72. data/node_modules/govuk-frontend/govuk/components/label/_label.scss +2 -45
  73. data/node_modules/govuk-frontend/govuk/components/notification-banner/_index.scss +89 -0
  74. data/node_modules/govuk-frontend/govuk/components/notification-banner/_notification-banner.scss +2 -0
  75. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +61 -0
  76. data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +44 -0
  77. data/node_modules/govuk-frontend/govuk/components/panel/_panel.scss +2 -44
  78. data/node_modules/govuk-frontend/govuk/components/phase-banner/_index.scss +27 -0
  79. data/node_modules/govuk-frontend/govuk/components/phase-banner/_phase-banner.scss +2 -31
  80. data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +342 -0
  81. data/node_modules/govuk-frontend/govuk/components/radios/_radios.scss +2 -346
  82. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +76 -28
  83. data/node_modules/govuk-frontend/govuk/components/select/_index.scss +49 -0
  84. data/node_modules/govuk-frontend/govuk/components/select/_select.scss +2 -57
  85. data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +36 -0
  86. data/node_modules/govuk-frontend/govuk/components/skip-link/_skip-link.scss +2 -37
  87. data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +145 -0
  88. data/node_modules/govuk-frontend/govuk/components/summary-list/_summary-list.scss +2 -157
  89. data/node_modules/govuk-frontend/govuk/components/table/_index.scss +71 -0
  90. data/node_modules/govuk-frontend/govuk/components/table/_table.scss +2 -54
  91. data/node_modules/govuk-frontend/govuk/components/tabs/_index.scss +130 -0
  92. data/node_modules/govuk-frontend/govuk/components/tabs/_tabs.scss +2 -142
  93. data/node_modules/govuk-frontend/govuk/components/tag/_index.scss +86 -0
  94. data/node_modules/govuk-frontend/govuk/components/tag/_tag.scss +2 -91
  95. data/node_modules/govuk-frontend/govuk/components/textarea/_index.scss +47 -0
  96. data/node_modules/govuk-frontend/govuk/components/textarea/_textarea.scss +2 -55
  97. data/node_modules/govuk-frontend/govuk/components/warning-text/_index.scss +66 -0
  98. data/node_modules/govuk-frontend/govuk/components/warning-text/_warning-text.scss +2 -60
  99. data/node_modules/govuk-frontend/govuk/core/_global-styles.scss +5 -3
  100. data/node_modules/govuk-frontend/govuk/core/_links.scss +13 -3
  101. data/node_modules/govuk-frontend/govuk/core/_lists.scss +17 -3
  102. data/node_modules/govuk-frontend/govuk/core/_section-break.scss +5 -3
  103. data/node_modules/govuk-frontend/govuk/core/_template.scss +5 -4
  104. data/node_modules/govuk-frontend/govuk/core/_typography.scss +5 -3
  105. data/node_modules/govuk-frontend/govuk/helpers/_clearfix.scss +1 -1
  106. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +1 -1
  107. data/node_modules/govuk-frontend/govuk/helpers/_device-pixels.scss +3 -3
  108. data/node_modules/govuk-frontend/govuk/helpers/_focused.scss +1 -1
  109. data/node_modules/govuk-frontend/govuk/helpers/_font-faces.scss +9 -11
  110. data/node_modules/govuk-frontend/govuk/helpers/_grid.scss +2 -1
  111. data/node_modules/govuk-frontend/govuk/helpers/_links.scss +246 -33
  112. data/node_modules/govuk-frontend/govuk/helpers/_media-queries.scss +2 -6
  113. data/node_modules/govuk-frontend/govuk/helpers/_shape-arrow.scss +1 -1
  114. data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +3 -2
  115. data/node_modules/govuk-frontend/govuk/helpers/_typography.scss +8 -7
  116. data/node_modules/govuk-frontend/govuk/helpers/_visually-hidden.scss +1 -1
  117. data/node_modules/govuk-frontend/govuk/objects/_all.scss +1 -0
  118. data/node_modules/govuk-frontend/govuk/objects/_button-group.scss +101 -0
  119. data/node_modules/govuk-frontend/govuk/objects/_form-group.scss +1 -4
  120. data/node_modules/govuk-frontend/govuk/objects/_grid.scss +3 -6
  121. data/node_modules/govuk-frontend/govuk/objects/_main-wrapper.scss +5 -4
  122. data/node_modules/govuk-frontend/govuk/objects/_width-container.scss +6 -4
  123. data/node_modules/govuk-frontend/govuk/overrides/_display.scss +6 -4
  124. data/node_modules/govuk-frontend/govuk/overrides/_spacing.scss +5 -3
  125. data/node_modules/govuk-frontend/govuk/overrides/_typography.scss +5 -3
  126. data/node_modules/govuk-frontend/govuk/overrides/_width.scss +6 -3
  127. data/node_modules/govuk-frontend/govuk/settings/_all.scss +2 -0
  128. data/node_modules/govuk-frontend/govuk/settings/_colours-applied.scss +11 -5
  129. data/node_modules/govuk-frontend/govuk/settings/_colours-organisations.scss +3 -0
  130. data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +42 -35
  131. data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +0 -1
  132. data/node_modules/govuk-frontend/govuk/settings/_ie8.scss +1 -1
  133. data/node_modules/govuk-frontend/govuk/settings/_links.scss +62 -0
  134. data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +4 -5
  135. data/node_modules/govuk-frontend/govuk/settings/_typography-font-families.scss +2 -2
  136. data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +14 -5
  137. data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +6 -2
  138. data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +1 -1
  139. data/node_modules/govuk-frontend/govuk/tools/_font-url.scss +1 -4
  140. data/node_modules/govuk-frontend/govuk/tools/_ie8.scss +1 -1
  141. data/node_modules/govuk-frontend/govuk/tools/_image-url.scss +1 -4
  142. data/node_modules/govuk-frontend/govuk/tools/_px-to-em.scss +1 -1
  143. data/node_modules/govuk-frontend/govuk/tools/_px-to-rem.scss +1 -1
  144. data/node_modules/govuk-frontend/govuk/utilities/_visually-hidden.scss +0 -1
  145. data/node_modules/govuk-frontend/govuk/vendor/_sass-mq.scss +0 -4
  146. data/package-lock.json +358 -288
  147. data/package.json +2 -2
  148. metadata +48 -67
@@ -0,0 +1,320 @@
1
+ @import "../error-message/index";
2
+ @import "../fieldset/index";
3
+ @import "../hint/index";
4
+ @import "../label/index";
5
+
6
+ @include govuk-exports("govuk/component/checkboxes") {
7
+
8
+ $govuk-touch-target-size: 44px;
9
+ $govuk-checkboxes-size: 40px;
10
+ $govuk-small-checkboxes-size: 24px;
11
+ $govuk-checkboxes-label-padding-left-right: govuk-spacing(3);
12
+
13
+ .govuk-checkboxes__item {
14
+ @include govuk-font($size: 19);
15
+
16
+ display: block;
17
+ position: relative;
18
+
19
+ min-height: $govuk-checkboxes-size;
20
+
21
+ margin-bottom: govuk-spacing(2);
22
+ padding-left: $govuk-checkboxes-size;
23
+
24
+ clear: left;
25
+ }
26
+
27
+ .govuk-checkboxes__item:last-child,
28
+ .govuk-checkboxes__item:last-of-type {
29
+ margin-bottom: 0;
30
+ }
31
+
32
+ .govuk-checkboxes__input {
33
+ $input-offset: ($govuk-touch-target-size - $govuk-checkboxes-size) / 2;
34
+
35
+ cursor: pointer;
36
+
37
+ // IE8 doesn’t support pseudo-elements, so we don’t want to hide native
38
+ // elements there.
39
+ @include govuk-not-ie8 {
40
+ position: absolute;
41
+
42
+ z-index: 1;
43
+ top: $input-offset * -1;
44
+ left: $input-offset * -1;
45
+
46
+ width: $govuk-touch-target-size;
47
+ height: $govuk-touch-target-size;
48
+ margin: 0;
49
+
50
+ opacity: 0;
51
+ }
52
+
53
+ @include govuk-if-ie8 {
54
+ margin-top: 10px;
55
+ margin-right: $govuk-checkboxes-size / -2;
56
+ margin-left: $govuk-checkboxes-size / -2;
57
+ float: left;
58
+
59
+ // add focus outline to input
60
+ &:focus {
61
+ outline: $govuk-focus-width solid $govuk-focus-colour;
62
+ }
63
+ }
64
+ }
65
+
66
+ .govuk-checkboxes__label {
67
+ display: inline-block;
68
+ margin-bottom: 0;
69
+ padding: 8px $govuk-checkboxes-label-padding-left-right govuk-spacing(1);
70
+ cursor: pointer;
71
+ // remove 300ms pause on mobile
72
+ -ms-touch-action: manipulation;
73
+ touch-action: manipulation;
74
+ }
75
+
76
+ @include govuk-not-ie8 {
77
+ // [ ] Check box
78
+ .govuk-checkboxes__label:before {
79
+ content: "";
80
+ box-sizing: border-box;
81
+ position: absolute;
82
+ top: 0;
83
+ left: 0;
84
+ width: $govuk-checkboxes-size;
85
+ height: $govuk-checkboxes-size;
86
+ border: $govuk-border-width-form-element solid currentColor;
87
+ background: transparent;
88
+ }
89
+
90
+ // ✔ Check mark
91
+ //
92
+ // The check mark is a box with a border on the left and bottom side (└──),
93
+ // rotated 45 degrees
94
+ .govuk-checkboxes__label:after {
95
+ content: "";
96
+ box-sizing: border-box;
97
+
98
+ position: absolute;
99
+ top: 11px;
100
+ left: 9px;
101
+ width: 23px;
102
+ height: 12px;
103
+
104
+ -webkit-transform: rotate(-45deg);
105
+
106
+ -ms-transform: rotate(-45deg);
107
+
108
+ transform: rotate(-45deg);
109
+ border: solid;
110
+ border-width: 0 0 5px 5px;
111
+ // Fix bug in IE11 caused by transform rotate (-45deg).
112
+ // See: alphagov/govuk_elements/issues/518
113
+ border-top-color: transparent;
114
+
115
+ opacity: 0;
116
+
117
+ background: transparent;
118
+ }
119
+ }
120
+
121
+ .govuk-checkboxes__hint {
122
+ display: block;
123
+ padding-right: $govuk-checkboxes-label-padding-left-right;
124
+ padding-left: $govuk-checkboxes-label-padding-left-right;
125
+ }
126
+
127
+ // Focused state
128
+ .govuk-checkboxes__input:focus + .govuk-checkboxes__label:before {
129
+ border-width: 4px;
130
+ box-shadow: 0 0 0 $govuk-focus-width $govuk-focus-colour;
131
+ }
132
+
133
+ // Selected state
134
+ .govuk-checkboxes__input:checked + .govuk-checkboxes__label:after {
135
+ opacity: 1;
136
+ }
137
+
138
+ // Disabled state
139
+ .govuk-checkboxes__input:disabled,
140
+ .govuk-checkboxes__input:disabled + .govuk-checkboxes__label {
141
+ cursor: default;
142
+ }
143
+
144
+ .govuk-checkboxes__input:disabled + .govuk-checkboxes__label {
145
+ opacity: .5;
146
+ }
147
+
148
+ // =========================================================
149
+ // Dividers ('or')
150
+ // =========================================================
151
+
152
+ .govuk-checkboxes__divider {
153
+ $govuk-divider-size: $govuk-checkboxes-size !default;
154
+ @include govuk-font($size: 19);
155
+ @include govuk-text-colour;
156
+ width: $govuk-divider-size;
157
+ margin-bottom: govuk-spacing(2);
158
+ text-align: center;
159
+ }
160
+
161
+ // =========================================================
162
+ // Conditional reveals
163
+ // =========================================================
164
+
165
+ // The narrow border is used in the conditional reveals because the border has
166
+ // to be an even number in order to be centred under the 40px checkbox or radio.
167
+ $conditional-border-width: $govuk-border-width-narrow;
168
+ // Calculate the amount of padding needed to keep the border centered against the checkbox.
169
+ $conditional-border-padding: ($govuk-checkboxes-size / 2) - ($conditional-border-width / 2);
170
+ // Move the border centered with the checkbox
171
+ $conditional-margin-left: $conditional-border-padding;
172
+ // Move the contents of the conditional inline with the label
173
+ $conditional-padding-left: $conditional-border-padding + $govuk-checkboxes-label-padding-left-right;
174
+
175
+ .govuk-checkboxes__conditional {
176
+ @include govuk-responsive-margin(4, "bottom");
177
+ margin-left: $conditional-margin-left;
178
+ padding-left: $conditional-padding-left;
179
+ border-left: $conditional-border-width solid $govuk-border-colour;
180
+
181
+ .js-enabled &--hidden {
182
+ display: none;
183
+ }
184
+
185
+ & > :last-child {
186
+ margin-bottom: 0;
187
+ }
188
+ }
189
+
190
+ // =========================================================
191
+ // Small checkboxes
192
+ // =========================================================
193
+
194
+ .govuk-checkboxes--small {
195
+
196
+ $input-offset: ($govuk-touch-target-size - $govuk-small-checkboxes-size) / 2;
197
+ $label-offset: $govuk-touch-target-size - $input-offset;
198
+
199
+ .govuk-checkboxes__item {
200
+ @include govuk-clearfix;
201
+ min-height: 0;
202
+ margin-bottom: 0;
203
+ padding-left: $label-offset;
204
+ float: left;
205
+ }
206
+
207
+ // Shift the touch target into the left margin so that the visible edge of
208
+ // the control is aligned
209
+ //
210
+ // ┆What colours do you like?
211
+ // ┌┆───┐
212
+ // │┆[] │ Purple
213
+ // └┆▲──┘
214
+ // ▲┆└─ Check box pseudo element, aligned with margin
215
+ // └─── Touch target (invisible input), shifted into the margin
216
+ .govuk-checkboxes__input {
217
+ @include govuk-not-ie8 {
218
+ left: $input-offset * -1;
219
+ }
220
+
221
+ @include govuk-if-ie8 {
222
+ margin-left: $govuk-small-checkboxes-size * -1;
223
+ }
224
+ }
225
+
226
+ // Adjust the size and position of the label.
227
+ //
228
+ // Unlike larger checkboxes, we also have to float the label in order to
229
+ // 'shrink' it, preventing the hover state from kicking in across the full
230
+ // width of the parent element.
231
+ .govuk-checkboxes__label {
232
+ margin-top: -2px;
233
+ padding: 13px govuk-spacing(3) 13px 1px;
234
+ float: left;
235
+
236
+ @include govuk-media-query($from: tablet) {
237
+ padding: 11px govuk-spacing(3) 10px 1px;
238
+ }
239
+ }
240
+
241
+ // [ ] Check box
242
+ //
243
+ // Reduce the size of the check box [1], vertically center it within the
244
+ // touch target [2]
245
+ .govuk-checkboxes__label:before {
246
+ top: $input-offset - $govuk-border-width-form-element; // 2
247
+ width: $govuk-small-checkboxes-size; // 1
248
+ height: $govuk-small-checkboxes-size; // 1
249
+ }
250
+
251
+ // ✔ Check mark
252
+ //
253
+ // Reduce the size of the check mark and re-align within the checkbox
254
+ .govuk-checkboxes__label:after {
255
+ top: 15px;
256
+ left: 6px;
257
+ width: 12px;
258
+ height: 6.5px;
259
+ border-width: 0 0 3px 3px;
260
+ }
261
+
262
+ // Fix position of hint with small checkboxes
263
+ //
264
+ // Do not use hints with small checkboxes – because they're within the input
265
+ // wrapper they trigger the hover state, but clicking them doesn't actually
266
+ // activate the control.
267
+ //
268
+ // (If you do use them, they won't look completely broken... but seriously,
269
+ // don't use them)
270
+ .govuk-checkboxes__hint {
271
+ padding: 0;
272
+ clear: both;
273
+ }
274
+
275
+ // Align conditional reveals with small checkboxes
276
+ .govuk-checkboxes__conditional {
277
+ $margin-left: ($govuk-small-checkboxes-size / 2) - ($conditional-border-width / 2);
278
+ margin-left: $margin-left;
279
+ padding-left: $label-offset - ($margin-left + $conditional-border-width);
280
+ clear: both;
281
+ }
282
+
283
+ // Hover state for small checkboxes.
284
+ //
285
+ // We use a hover state for small checkboxes because the touch target size
286
+ // is so much larger than their visible size, and so we need to provide
287
+ // feedback to the user as to which checkbox they will select when their
288
+ // cursor is outside of the visible area.
289
+ .govuk-checkboxes__item:hover .govuk-checkboxes__input:not(:disabled) + .govuk-checkboxes__label:before {
290
+ box-shadow: 0 0 0 $govuk-hover-width $govuk-hover-colour;
291
+ }
292
+
293
+ // Because we've overridden the border-shadow provided by the focus state,
294
+ // we need to redefine that too.
295
+ //
296
+ // We use two box shadows, one that restores the original focus state [1]
297
+ // and another that then applies the hover state [2].
298
+ .govuk-checkboxes__item:hover .govuk-checkboxes__input:focus + .govuk-checkboxes__label:before {
299
+ box-shadow:
300
+ 0 0 0 $govuk-focus-width $govuk-focus-colour, // 1
301
+ 0 0 0 $govuk-hover-width $govuk-hover-colour; // 2
302
+ }
303
+
304
+ // For devices that explicitly don't support hover, don't provide a hover
305
+ // state (e.g. on touch devices like iOS).
306
+ //
307
+ // We can't use `@media (hover: hover)` because we wouldn't get the hover
308
+ // state in browsers that don't support `@media (hover)` (like Internet
309
+ // Explorer) – so we have to 'undo' the hover state instead.
310
+ @media (hover: none), (pointer: coarse) {
311
+ .govuk-checkboxes__item:hover .govuk-checkboxes__input:not(:disabled) + .govuk-checkboxes__label:before {
312
+ box-shadow: initial;
313
+ }
314
+
315
+ .govuk-checkboxes__item:hover .govuk-checkboxes__input:focus + .govuk-checkboxes__label:before {
316
+ box-shadow: 0 0 0 $govuk-focus-width $govuk-focus-colour;
317
+ }
318
+ }
319
+ }
320
+ }
@@ -1033,52 +1033,157 @@ function Checkboxes ($module) {
1033
1033
  this.$inputs = $module.querySelectorAll('input[type="checkbox"]');
1034
1034
  }
1035
1035
 
1036
+ /**
1037
+ * Initialise Checkboxes
1038
+ *
1039
+ * Checkboxes can be associated with a 'conditionally revealed' content block –
1040
+ * for example, a checkbox for 'Phone' could reveal an additional form field for
1041
+ * the user to enter their phone number.
1042
+ *
1043
+ * These associations are made using a `data-aria-controls` attribute, which is
1044
+ * promoted to an aria-controls attribute during initialisation.
1045
+ *
1046
+ * We also need to restore the state of any conditional reveals on the page (for
1047
+ * example if the user has navigated back), and set up event handlers to keep
1048
+ * the reveal in sync with the checkbox state.
1049
+ */
1036
1050
  Checkboxes.prototype.init = function () {
1037
1051
  var $module = this.$module;
1038
1052
  var $inputs = this.$inputs;
1039
1053
 
1040
- /**
1041
- * Loop over all items with [data-controls]
1042
- * Check if they have a matching conditional reveal
1043
- * If they do, assign attributes.
1044
- **/
1045
1054
  nodeListForEach($inputs, function ($input) {
1046
- var controls = $input.getAttribute('data-aria-controls');
1055
+ var target = $input.getAttribute('data-aria-controls');
1047
1056
 
1048
- // Check if input controls anything
1049
- // Check if content exists, before setting attributes.
1050
- if (!controls || !$module.querySelector('#' + controls)) {
1057
+ // Skip checkboxes without data-aria-controls attributes, or where the
1058
+ // target element does not exist.
1059
+ if (!target || !$module.querySelector('#' + target)) {
1051
1060
  return
1052
1061
  }
1053
1062
 
1054
- // If we have content that is controlled, set attributes.
1055
- $input.setAttribute('aria-controls', controls);
1063
+ // Promote the data-aria-controls attribute to a aria-controls attribute
1064
+ // so that the relationship is exposed in the AOM
1065
+ $input.setAttribute('aria-controls', target);
1056
1066
  $input.removeAttribute('data-aria-controls');
1057
- this.setAttributes($input);
1058
- }.bind(this));
1067
+ });
1068
+
1069
+ // When the page is restored after navigating 'back' in some browsers the
1070
+ // state of form controls is not restored until *after* the DOMContentLoaded
1071
+ // event is fired, so we need to sync after the pageshow event in browsers
1072
+ // that support it.
1073
+ if ('onpageshow' in window) {
1074
+ window.addEventListener('pageshow', this.syncAllConditionalReveals.bind(this));
1075
+ } else {
1076
+ window.addEventListener('DOMContentLoaded', this.syncAllConditionalReveals.bind(this));
1077
+ }
1078
+
1079
+ // Although we've set up handlers to sync state on the pageshow or
1080
+ // DOMContentLoaded event, init could be called after those events have fired,
1081
+ // for example if they are added to the page dynamically, so sync now too.
1082
+ this.syncAllConditionalReveals();
1059
1083
 
1060
- // Handle events
1061
1084
  $module.addEventListener('click', this.handleClick.bind(this));
1062
1085
  };
1063
1086
 
1064
- Checkboxes.prototype.setAttributes = function ($input) {
1065
- var inputIsChecked = $input.checked;
1066
- $input.setAttribute('aria-expanded', inputIsChecked);
1087
+ /**
1088
+ * Sync the conditional reveal states for all inputs in this $module.
1089
+ */
1090
+ Checkboxes.prototype.syncAllConditionalReveals = function () {
1091
+ nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this));
1092
+ };
1093
+
1094
+ /**
1095
+ * Sync conditional reveal with the input state
1096
+ *
1097
+ * Synchronise the visibility of the conditional reveal, and its accessible
1098
+ * state, with the input's checked state.
1099
+ *
1100
+ * @param {HTMLInputElement} $input Checkbox input
1101
+ */
1102
+ Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
1103
+ var $target = this.$module.querySelector('#' + $input.getAttribute('aria-controls'));
1067
1104
 
1068
- var $content = this.$module.querySelector('#' + $input.getAttribute('aria-controls'));
1069
- if ($content) {
1070
- $content.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked);
1105
+ if ($target && $target.classList.contains('govuk-checkboxes__conditional')) {
1106
+ var inputIsChecked = $input.checked;
1107
+
1108
+ $input.setAttribute('aria-expanded', inputIsChecked);
1109
+ $target.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked);
1071
1110
  }
1072
1111
  };
1073
1112
 
1113
+ /**
1114
+ * Uncheck other checkboxes
1115
+ *
1116
+ * Find any other checkbox inputs with the same name value, and uncheck them.
1117
+ * This is useful for when a “None of these" checkbox is checked.
1118
+ */
1119
+ Checkboxes.prototype.unCheckAllInputsExcept = function ($input) {
1120
+ var allInputsWithSameName = document.querySelectorAll('input[type="checkbox"][name="' + $input.name + '"]');
1121
+
1122
+ nodeListForEach(allInputsWithSameName, function ($inputWithSameName) {
1123
+ var hasSameFormOwner = ($input.form === $inputWithSameName.form);
1124
+ if (hasSameFormOwner && $inputWithSameName !== $input) {
1125
+ $inputWithSameName.checked = false;
1126
+ }
1127
+ });
1128
+
1129
+ this.syncAllConditionalReveals();
1130
+ };
1131
+
1132
+ /**
1133
+ * Uncheck exclusive inputs
1134
+ *
1135
+ * Find any checkbox inputs with the same name value and the 'exclusive' behaviour,
1136
+ * and uncheck them. This helps prevent someone checking both a regular checkbox and a
1137
+ * "None of these" checkbox in the same fieldset.
1138
+ */
1139
+ Checkboxes.prototype.unCheckExclusiveInputs = function ($input) {
1140
+ var allInputsWithSameNameAndExclusiveBehaviour = document.querySelectorAll(
1141
+ 'input[data-behaviour="exclusive"][type="checkbox"][name="' + $input.name + '"]'
1142
+ );
1143
+
1144
+ nodeListForEach(allInputsWithSameNameAndExclusiveBehaviour, function ($exclusiveInput) {
1145
+ var hasSameFormOwner = ($input.form === $exclusiveInput.form);
1146
+ if (hasSameFormOwner) {
1147
+ $exclusiveInput.checked = false;
1148
+ }
1149
+ });
1150
+
1151
+ this.syncAllConditionalReveals();
1152
+ };
1153
+
1154
+ /**
1155
+ * Click event handler
1156
+ *
1157
+ * Handle a click within the $module – if the click occurred on a checkbox, sync
1158
+ * the state of any associated conditional reveal with the checkbox state.
1159
+ *
1160
+ * @param {MouseEvent} event Click event
1161
+ */
1074
1162
  Checkboxes.prototype.handleClick = function (event) {
1075
1163
  var $target = event.target;
1076
1164
 
1077
- // If a checkbox with aria-controls, handle click
1078
- var isCheckbox = $target.getAttribute('type') === 'checkbox';
1165
+ // Ignore clicks on things that aren't checkbox inputs
1166
+ if ($target.type !== 'checkbox') {
1167
+ return
1168
+ }
1169
+
1170
+ // If the checkbox conditionally-reveals some content, sync the state
1079
1171
  var hasAriaControls = $target.getAttribute('aria-controls');
1080
- if (isCheckbox && hasAriaControls) {
1081
- this.setAttributes($target);
1172
+ if (hasAriaControls) {
1173
+ this.syncConditionalRevealWithInputState($target);
1174
+ }
1175
+
1176
+ // No further behaviour needed for unchecking
1177
+ if (!$target.checked) {
1178
+ return
1179
+ }
1180
+
1181
+ // Handle 'exclusive' checkbox behaviour (ie "None of these")
1182
+ var hasBehaviourExclusive = ($target.getAttribute('data-behaviour') === 'exclusive');
1183
+ if (hasBehaviourExclusive) {
1184
+ this.unCheckAllInputsExcept($target);
1185
+ } else {
1186
+ this.unCheckExclusiveInputs($target);
1082
1187
  }
1083
1188
  };
1084
1189