govuk_tech_docs 3.2.1 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/publish.yaml +1 -1
  3. data/CHANGELOG.md +26 -7
  4. data/README.md +2 -2
  5. data/lib/assets/javascripts/_modules/search.js +2 -2
  6. data/lib/govuk_tech_docs/contribution_banner.rb +1 -1
  7. data/lib/govuk_tech_docs/version.rb +1 -1
  8. data/lib/source/layouts/core.erb +1 -1
  9. data/node_modules/govuk-frontend/govuk/all.js +1548 -311
  10. data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +70 -0
  11. data/node_modules/govuk-frontend/govuk/common/index.js +172 -0
  12. data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +373 -0
  13. data/node_modules/govuk-frontend/govuk/common.js +138 -3
  14. data/node_modules/govuk-frontend/govuk/components/_all.scss +1 -0
  15. data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +5 -6
  16. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +754 -36
  17. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +0 -2
  18. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +29 -21
  19. data/node_modules/govuk-frontend/govuk/components/button/button.js +365 -107
  20. data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +9 -0
  21. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +1092 -109
  22. data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +3 -2
  23. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +30 -2
  24. data/node_modules/govuk-frontend/govuk/components/details/details.js +51 -33
  25. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +289 -6
  26. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +13 -23
  27. data/node_modules/govuk-frontend/govuk/components/header/_index.scss +30 -24
  28. data/node_modules/govuk-frontend/govuk/components/header/header.js +59 -11
  29. data/node_modules/govuk-frontend/govuk/components/input/_index.scss +13 -23
  30. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +252 -2
  31. data/node_modules/govuk-frontend/govuk/components/pagination/_index.scss +247 -0
  32. data/node_modules/govuk-frontend/govuk/components/pagination/_pagination.scss +2 -0
  33. data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +1 -1
  34. data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +5 -12
  35. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +30 -2
  36. data/node_modules/govuk-frontend/govuk/components/select/_index.scss +11 -0
  37. data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +1 -3
  38. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +10 -4
  39. data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +45 -13
  40. data/node_modules/govuk-frontend/govuk/components/table/_index.scss +1 -1
  41. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +28 -0
  42. data/node_modules/govuk-frontend/govuk/core/_section-break.scss +1 -1
  43. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +5 -5
  44. data/node_modules/govuk-frontend/govuk/helpers/_focused.scss +5 -0
  45. data/node_modules/govuk-frontend/govuk/helpers/_links.scss +13 -11
  46. data/node_modules/govuk-frontend/govuk/helpers/_media-queries.scss +2 -2
  47. data/node_modules/govuk-frontend/govuk/helpers/_shape-arrow.scss +1 -1
  48. data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +3 -3
  49. data/node_modules/govuk-frontend/govuk/helpers/_typography.scss +16 -9
  50. data/node_modules/govuk-frontend/govuk/i18n.js +390 -0
  51. data/node_modules/govuk-frontend/govuk/objects/_button-group.scss +10 -26
  52. data/node_modules/govuk-frontend/govuk/objects/_template.scss +1 -1
  53. data/node_modules/govuk-frontend/govuk/objects/_width-container.scss +0 -4
  54. data/node_modules/govuk-frontend/govuk/overrides/_spacing.scss +56 -12
  55. data/node_modules/govuk-frontend/govuk/settings/_all.scss +1 -0
  56. data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +12 -0
  57. data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +26 -0
  58. data/node_modules/govuk-frontend/govuk/settings/_spacing.scss +4 -8
  59. data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +23 -0
  60. data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +12 -0
  61. data/node_modules/govuk-frontend/govuk/settings/_warnings.scss +53 -0
  62. data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +20 -6
  63. data/node_modules/govuk-frontend/govuk/tools/_exports.scss +1 -1
  64. data/node_modules/govuk-frontend/govuk/tools/_font-url.scss +1 -1
  65. data/node_modules/govuk-frontend/govuk/tools/_image-url.scss +1 -1
  66. data/node_modules/govuk-frontend/govuk/tools/_px-to-em.scss +2 -2
  67. data/node_modules/govuk-frontend/govuk/tools/_px-to-rem.scss +1 -1
  68. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +21 -0
  69. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +300 -0
  70. data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +21 -0
  71. data/node_modules/govuk-frontend/govuk-prototype-kit/init.js +7 -0
  72. data/node_modules/govuk-frontend/govuk-prototype-kit/init.scss +12 -0
  73. data/package-lock.json +12 -12
  74. data/package.json +1 -1
  75. metadata +14 -2
@@ -30,12 +30,12 @@
30
30
  @mixin govuk-link-decoration {
31
31
  text-decoration: underline;
32
32
 
33
- @if ($govuk-new-link-styles) {
34
- @if ($govuk-link-underline-thickness) {
33
+ @if $govuk-new-link-styles {
34
+ @if $govuk-link-underline-thickness {
35
35
  text-decoration-thickness: $govuk-link-underline-thickness;
36
36
  }
37
37
 
38
- @if ($govuk-link-underline-offset) {
38
+ @if $govuk-link-underline-offset {
39
39
  text-underline-offset: $govuk-link-underline-offset;
40
40
  }
41
41
  }
@@ -50,7 +50,7 @@
50
50
  /// @access public
51
51
 
52
52
  @mixin govuk-link-hover-decoration {
53
- @if ($govuk-new-link-styles and $govuk-link-hover-underline-thickness) {
53
+ @if $govuk-new-link-styles and $govuk-link-hover-underline-thickness {
54
54
  text-decoration-thickness: $govuk-link-hover-underline-thickness;
55
55
  // Disable ink skipping on underlines on hover. Browsers haven't
56
56
  // standardised on this part of the spec yet, so set both properties
@@ -104,7 +104,7 @@
104
104
  // we need to override the text colour for that combination of selectors so
105
105
  // so that unvisited links styled as buttons do not end up with dark blue
106
106
  // text when focussed.
107
- @include govuk-compatibility(govuk_template) {
107
+ @include _govuk-compatibility(govuk_template) {
108
108
  &:link:focus {
109
109
  color: $govuk-focus-text-colour;
110
110
  }
@@ -152,7 +152,7 @@
152
152
  // we need to override the text colour for that combination of selectors so
153
153
  // so that unvisited links styled as buttons do not end up with dark blue
154
154
  // text when focussed.
155
- @include govuk-compatibility(govuk_template) {
155
+ @include _govuk-compatibility(govuk_template) {
156
156
  &:link:focus {
157
157
  color: $govuk-focus-text-colour;
158
158
  }
@@ -200,7 +200,7 @@
200
200
  // we need to override the text colour for that combination of selectors so
201
201
  // so that unvisited links styled as buttons do not end up with dark blue
202
202
  // text when focussed.
203
- @include govuk-compatibility(govuk_template) {
203
+ @include _govuk-compatibility(govuk_template) {
204
204
  &:link:focus {
205
205
  color: $govuk-focus-text-colour;
206
206
  }
@@ -243,7 +243,7 @@
243
243
  // alphagov/govuk_template includes a specific a:link:focus selector designed
244
244
  // to make unvisited links a slightly darker blue when focussed, so we need to
245
245
  // override the text colour for that combination of selectors.
246
- @include govuk-compatibility(govuk_template) {
246
+ @include _govuk-compatibility(govuk_template) {
247
247
  &:link:focus {
248
248
  @include govuk-text-colour;
249
249
  }
@@ -275,7 +275,9 @@
275
275
  // Force a colour change on hover to work around a bug in Safari
276
276
  // https://bugs.webkit.org/show_bug.cgi?id=224483
277
277
  &:hover {
278
- color: rgba($govuk-text-colour, .99);
278
+ @if type-of($govuk-text-colour) == color {
279
+ color: rgba($govuk-text-colour, .99);
280
+ }
279
281
  }
280
282
 
281
283
  &:active,
@@ -286,7 +288,7 @@
286
288
  // alphagov/govuk_template includes a specific a:link:focus selector designed
287
289
  // to make unvisited links a slightly darker blue when focussed, so we need to
288
290
  // override the text colour for that combination of selectors.
289
- @include govuk-compatibility(govuk_template) {
291
+ @include _govuk-compatibility(govuk_template) {
290
292
  &:link:focus {
291
293
  @include govuk-text-colour;
292
294
  }
@@ -329,7 +331,7 @@
329
331
  // alphagov/govuk_template includes a specific a:link:focus selector designed
330
332
  // to make unvisited links a slightly darker blue when focussed, so we need to
331
333
  // override the text colour for that combination of selectors.
332
- @include govuk-compatibility(govuk_template) {
334
+ @include _govuk-compatibility(govuk_template) {
333
335
  &:link:focus {
334
336
  color: $govuk-focus-text-colour;
335
337
  }
@@ -12,7 +12,7 @@ $mq-static-breakpoint: if(variable-exists(govuk-ie8-breakpoint), $govuk-ie8-brea
12
12
 
13
13
  $mq-show-breakpoints: ();
14
14
 
15
- @if (variable-exists(govuk-show-breakpoints) and $govuk-show-breakpoints) {
15
+ @if variable-exists(govuk-show-breakpoints) and $govuk-show-breakpoints {
16
16
  $mq-show-breakpoints: map-keys($govuk-breakpoints);
17
17
  }
18
18
 
@@ -20,7 +20,7 @@ $mq-show-breakpoints: ();
20
20
  // 'rasterize' any media queries.
21
21
 
22
22
  $mq-responsive: true;
23
- @if (variable-exists(govuk-is-ie8) and $govuk-is-ie8) {
23
+ @if variable-exists(govuk-is-ie8) and $govuk-is-ie8 {
24
24
  $mq-responsive: false;
25
25
  }
26
26
 
@@ -46,7 +46,7 @@
46
46
 
47
47
  $perpendicular: $base / 2;
48
48
 
49
- @if ($height == null) {
49
+ @if not $height {
50
50
  $height: _govuk-equilateral-height($base);
51
51
  }
52
52
 
@@ -39,7 +39,7 @@
39
39
  }
40
40
 
41
41
  $is-negative: false;
42
- @if ($spacing-point < 0) {
42
+ @if $spacing-point < 0 {
43
43
  $is-negative: true;
44
44
  $spacing-point: abs($spacing-point);
45
45
  }
@@ -94,12 +94,12 @@
94
94
  // Loop through each breakpoint in the map
95
95
  @each $breakpoint, $breakpoint-value in $scale-map {
96
96
 
97
- @if ($adjustment) {
97
+ @if $adjustment {
98
98
  $breakpoint-value: $breakpoint-value + $adjustment;
99
99
  }
100
100
 
101
101
  // The 'null' breakpoint is for mobile.
102
- @if $breakpoint == null {
102
+ @if not $breakpoint {
103
103
 
104
104
  @if $direction == all {
105
105
  #{$property}: $breakpoint-value if($important, !important, null);
@@ -23,7 +23,7 @@
23
23
  // We do not need to include the GDS Transport font-face declarations if
24
24
  // alphagov/govuk_template is being used since nta will already be included by
25
25
  // default.
26
- @if ($govuk-include-default-font-face) {
26
+ @if $govuk-include-default-font-face {
27
27
  @include _govuk-font-face-gds-transport;
28
28
  }
29
29
 
@@ -86,12 +86,13 @@
86
86
 
87
87
  /// Responsive typography helper
88
88
  ///
89
- /// Takes a 'font map' as an argument and uses it to create font-size and
90
- /// line-height declarations for different breakpoints, and for print.
89
+ /// Takes a point from the responsive 'font map' as an argument (the size as it
90
+ /// would appear on tablet and above), and uses it to create font-size and
91
+ /// line-height declarations for different breakpoints, and print.
91
92
  ///
92
93
  /// Example font map:
93
94
  ///
94
- /// $my-font-map: (
95
+ /// 19: (
95
96
  /// null: (
96
97
  /// font-size: 16px,
97
98
  /// line-height: 20px
@@ -106,12 +107,15 @@
106
107
  /// )
107
108
  /// );
108
109
  ///
109
- /// @param {Map} $font-map - Font map
110
+ /// @param {Number} $size - Point from the spacing scale (the size as it would
111
+ /// appear on tablet and above)
110
112
  /// @param {Number} $override-line-height [false] - Non responsive custom line
111
113
  /// height. Omit to use the line height from the font map.
112
114
  /// @param {Boolean} $important [false] - Whether to mark declarations as
113
115
  /// `!important`.
114
116
  ///
117
+ /// @throw if `$size` is not a valid point from the spacing scale
118
+ ///
115
119
  /// @access public
116
120
 
117
121
  @mixin govuk-typography-responsive($size, $override-line-height: false, $important: false) {
@@ -142,7 +146,7 @@
142
146
  $font-size-rem: $font-size-rem if($important, !important, null);
143
147
  $line-height: $line-height if($important, !important, null);
144
148
 
145
- @if $breakpoint == null {
149
+ @if not $breakpoint {
146
150
  font-size: $font-size;
147
151
  @if $govuk-typography-use-rem {
148
152
  font-size: $font-size-rem;
@@ -167,11 +171,14 @@
167
171
 
168
172
  /// Font helper
169
173
  ///
170
- /// @param {Number} $size - Size of the font as it would appear on desktop -
171
- /// uses the responsive font size map
174
+ /// @param {Number | Boolean} $size Point from the spacing scale (the size as it
175
+ /// would appear on tablet and above). Use `false` to avoid setting a size.
172
176
  /// @param {String} $weight [regular] - Weight: `bold` or `regular`
173
177
  /// @param {Boolean} $tabular [false] - Whether to use tabular numbers or not
174
- /// @param {Number} $line-height [false] - Line-height, if overriding the default
178
+ /// @param {Number} $line-height [false] - Line-height, if overriding the
179
+ /// default
180
+ ///
181
+ /// @throw if `$size` is not a valid point from the spacing scale (or false)
175
182
  ///
176
183
  /// @access public
177
184
 
@@ -0,0 +1,390 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define('GOVUKFrontend', ['exports'], factory) :
4
+ (factory((global.GOVUKFrontend = {})));
5
+ }(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * Internal support for selecting messages to render, with placeholder
9
+ * interpolation and locale-aware number formatting and pluralisation
10
+ *
11
+ * @class
12
+ * @private
13
+ * @param {TranslationsFlattened} translations - Key-value pairs of the translation strings to use.
14
+ * @param {object} [config] - Configuration options for the function.
15
+ * @param {string} config.locale - An overriding locale for the PluralRules functionality.
16
+ */
17
+ function I18n (translations, config) {
18
+ // Make list of translations available throughout function
19
+ this.translations = translations || {};
20
+
21
+ // The locale to use for PluralRules and NumberFormat
22
+ this.locale = (config && config.locale) || document.documentElement.lang || 'en';
23
+ }
24
+
25
+ /**
26
+ * The most used function - takes the key for a given piece of UI text and
27
+ * returns the appropriate string.
28
+ *
29
+ * @param {string} lookupKey - The lookup key of the string to use.
30
+ * @param {object} options - Any options passed with the translation string, e.g: for string interpolation.
31
+ * @returns {string} The appropriate translation string.
32
+ */
33
+ I18n.prototype.t = function (lookupKey, options) {
34
+ if (!lookupKey) {
35
+ // Print a console error if no lookup key has been provided
36
+ throw new Error('i18n: lookup key missing')
37
+ }
38
+
39
+ // If the `count` option is set, determine which plural suffix is needed and
40
+ // change the lookupKey to match. We check to see if it's undefined instead of
41
+ // falsy, as this could legitimately be 0.
42
+ if (options && typeof options.count !== 'undefined') {
43
+ // Get the plural suffix
44
+ lookupKey = lookupKey + '.' + this.getPluralSuffix(lookupKey, options.count);
45
+ }
46
+
47
+ if (lookupKey in this.translations) {
48
+ // Fetch the translation string for that lookup key
49
+ var translationString = this.translations[lookupKey];
50
+
51
+ // Check for ${} placeholders in the translation string
52
+ if (translationString.match(/%{(.\S+)}/)) {
53
+ if (!options) {
54
+ throw new Error('i18n: cannot replace placeholders in string if no option data provided')
55
+ }
56
+
57
+ return this.replacePlaceholders(translationString, options)
58
+ } else {
59
+ return translationString
60
+ }
61
+ } else {
62
+ // If the key wasn't found in our translations object,
63
+ // return the lookup key itself as the fallback
64
+ return lookupKey
65
+ }
66
+ };
67
+
68
+ /**
69
+ * Takes a translation string with placeholders, and replaces the placeholders
70
+ * with the provided data
71
+ *
72
+ * @param {string} translationString - The translation string
73
+ * @param {object} options - Any options passed with the translation string, e.g: for string interpolation.
74
+ * @returns {string} The translation string to output, with ${} placeholders replaced
75
+ */
76
+ I18n.prototype.replacePlaceholders = function (translationString, options) {
77
+ var formatter;
78
+
79
+ if (this.hasIntlNumberFormatSupport()) {
80
+ formatter = new Intl.NumberFormat(this.locale);
81
+ }
82
+
83
+ return translationString.replace(/%{(.\S+)}/g, function (placeholderWithBraces, placeholderKey) {
84
+ if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
85
+ var placeholderValue = options[placeholderKey];
86
+
87
+ // If a user has passed `false` as the value for the placeholder
88
+ // treat it as though the value should not be displayed
89
+ if (placeholderValue === false) {
90
+ return ''
91
+ }
92
+
93
+ // If the placeholder's value is a number, localise the number formatting
94
+ if (typeof placeholderValue === 'number' && formatter) {
95
+ return formatter.format(placeholderValue)
96
+ }
97
+
98
+ return placeholderValue
99
+ } else {
100
+ throw new Error('i18n: no data found to replace ' + placeholderWithBraces + ' placeholder in string')
101
+ }
102
+ })
103
+ };
104
+
105
+ /**
106
+ * Check to see if the browser supports Intl and Intl.PluralRules.
107
+ *
108
+ * It requires all conditions to be met in order to be supported:
109
+ * - The browser supports the Intl class (true in IE11)
110
+ * - The implementation of Intl supports PluralRules (NOT true in IE11)
111
+ * - The browser/OS has plural rules for the current locale (browser dependent)
112
+ *
113
+ * @returns {boolean} Returns true if all conditions are met. Returns false otherwise.
114
+ */
115
+ I18n.prototype.hasIntlPluralRulesSupport = function () {
116
+ return Boolean(window.Intl && ('PluralRules' in window.Intl && Intl.PluralRules.supportedLocalesOf(this.locale).length))
117
+ };
118
+
119
+ /**
120
+ * Check to see if the browser supports Intl and Intl.NumberFormat.
121
+ *
122
+ * It requires all conditions to be met in order to be supported:
123
+ * - The browser supports the Intl class (true in IE11)
124
+ * - The implementation of Intl supports NumberFormat (also true in IE11)
125
+ * - The browser/OS has number formatting rules for the current locale (browser dependent)
126
+ *
127
+ * @returns {boolean} Returns true if all conditions are met. Returns false otherwise.
128
+ */
129
+ I18n.prototype.hasIntlNumberFormatSupport = function () {
130
+ return Boolean(window.Intl && ('NumberFormat' in window.Intl && Intl.NumberFormat.supportedLocalesOf(this.locale).length))
131
+ };
132
+
133
+ /**
134
+ * Get the appropriate suffix for the plural form.
135
+ *
136
+ * Uses Intl.PluralRules (or our own fallback implementation) to get the
137
+ * 'preferred' form to use for the given count.
138
+ *
139
+ * Checks that a translation has been provided for that plural form – if it
140
+ * hasn't, it'll fall back to the 'other' plural form (unless that doesn't exist
141
+ * either, in which case an error will be thrown)
142
+ *
143
+ * @param {string} lookupKey - The lookup key of the string to use.
144
+ * @param {number} count - Number used to determine which pluralisation to use.
145
+ * @returns {PluralRule} The suffix associated with the correct pluralisation for this locale.
146
+ */
147
+ I18n.prototype.getPluralSuffix = function (lookupKey, count) {
148
+ // Validate that the number is actually a number.
149
+ //
150
+ // Number(count) will turn anything that can't be converted to a Number type
151
+ // into 'NaN'. isFinite filters out NaN, as it isn't a finite number.
152
+ count = Number(count);
153
+ if (!isFinite(count)) { return 'other' }
154
+
155
+ var preferredForm;
156
+
157
+ // Check to verify that all the requirements for Intl.PluralRules are met.
158
+ // If so, we can use that instead of our custom implementation. Otherwise,
159
+ // use the hardcoded fallback.
160
+ if (this.hasIntlPluralRulesSupport()) {
161
+ preferredForm = new Intl.PluralRules(this.locale).select(count);
162
+ } else {
163
+ preferredForm = this.selectPluralFormUsingFallbackRules(count);
164
+ }
165
+
166
+ // Use the correct plural form if provided
167
+ if (lookupKey + '.' + preferredForm in this.translations) {
168
+ return preferredForm
169
+ // Fall back to `other` if the plural form is missing, but log a warning
170
+ // to the console
171
+ } else if (lookupKey + '.other' in this.translations) {
172
+ if (console && 'warn' in console) {
173
+ console.warn('i18n: Missing plural form ".' + preferredForm + '" for "' +
174
+ this.locale + '" locale. Falling back to ".other".');
175
+ }
176
+
177
+ return 'other'
178
+ // If the required `other` plural form is missing, all we can do is error
179
+ } else {
180
+ throw new Error(
181
+ 'i18n: Plural form ".other" is required for "' + this.locale + '" locale'
182
+ )
183
+ }
184
+ };
185
+
186
+ /**
187
+ * Get the plural form using our fallback implementation
188
+ *
189
+ * This is split out into a separate function to make it easier to test the
190
+ * fallback behaviour in an environment where Intl.PluralRules exists.
191
+ *
192
+ * @param {number} count - Number used to determine which pluralisation to use.
193
+ * @returns {PluralRule} The pluralisation form for count in this locale.
194
+ */
195
+ I18n.prototype.selectPluralFormUsingFallbackRules = function (count) {
196
+ // Currently our custom code can only handle positive integers, so let's
197
+ // make sure our number is one of those.
198
+ count = Math.abs(Math.floor(count));
199
+
200
+ var ruleset = this.getPluralRulesForLocale();
201
+
202
+ if (ruleset) {
203
+ return I18n.pluralRules[ruleset](count)
204
+ }
205
+
206
+ return 'other'
207
+ };
208
+
209
+ /**
210
+ * Work out which pluralisation rules to use for the current locale
211
+ *
212
+ * The locale may include a regional indicator (such as en-GB), but we don't
213
+ * usually care about this part, as pluralisation rules are usually the same
214
+ * regardless of region. There are exceptions, however, (e.g. Portuguese) so
215
+ * this searches by both the full and shortened locale codes, just to be sure.
216
+ *
217
+ * @returns {PluralRuleName | undefined} The name of the pluralisation rule to use (a key for one
218
+ * of the functions in this.pluralRules)
219
+ */
220
+ I18n.prototype.getPluralRulesForLocale = function () {
221
+ var locale = this.locale;
222
+ var localeShort = locale.split('-')[0];
223
+
224
+ // Look through the plural rules map to find which `pluralRule` is
225
+ // appropriate for our current `locale`.
226
+ for (var pluralRule in I18n.pluralRulesMap) {
227
+ if (Object.prototype.hasOwnProperty.call(I18n.pluralRulesMap, pluralRule)) {
228
+ var languages = I18n.pluralRulesMap[pluralRule];
229
+ for (var i = 0; i < languages.length; i++) {
230
+ if (languages[i] === locale || languages[i] === localeShort) {
231
+ return pluralRule
232
+ }
233
+ }
234
+ }
235
+ }
236
+ };
237
+
238
+ /**
239
+ * Map of plural rules to languages where those rules apply.
240
+ *
241
+ * Note: These groups are named for the most dominant or recognisable language
242
+ * that uses each system. The groupings do not imply that the languages are
243
+ * related to one another. Many languages have evolved the same systems
244
+ * independently of one another.
245
+ *
246
+ * Code to support more languages can be found in the i18n spike:
247
+ * {@link https://github.com/alphagov/govuk-frontend/blob/spike-i18n-support/src/govuk/i18n.mjs}
248
+ *
249
+ * Languages currently supported:
250
+ *
251
+ * Arabic: Arabic (ar)
252
+ * Chinese: Burmese (my), Chinese (zh), Indonesian (id), Japanese (ja),
253
+ * Javanese (jv), Korean (ko), Malay (ms), Thai (th), Vietnamese (vi)
254
+ * French: Armenian (hy), Bangla (bn), French (fr), Gujarati (gu), Hindi (hi),
255
+ * Persian Farsi (fa), Punjabi (pa), Zulu (zu)
256
+ * German: Afrikaans (af), Albanian (sq), Azerbaijani (az), Basque (eu),
257
+ * Bulgarian (bg), Catalan (ca), Danish (da), Dutch (nl), English (en),
258
+ * Estonian (et), Finnish (fi), Georgian (ka), German (de), Greek (el),
259
+ * Hungarian (hu), Luxembourgish (lb), Norwegian (no), Somali (so),
260
+ * Swahili (sw), Swedish (sv), Tamil (ta), Telugu (te), Turkish (tr),
261
+ * Urdu (ur)
262
+ * Irish: Irish Gaelic (ga)
263
+ * Russian: Russian (ru), Ukrainian (uk)
264
+ * Scottish: Scottish Gaelic (gd)
265
+ * Spanish: European Portuguese (pt-PT), Italian (it), Spanish (es)
266
+ * Welsh: Welsh (cy)
267
+ *
268
+ * @type {Object<PluralRuleName, string[]>}
269
+ */
270
+ I18n.pluralRulesMap = {
271
+ arabic: ['ar'],
272
+ chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
273
+ french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
274
+ german: [
275
+ 'af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka',
276
+ 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'
277
+ ],
278
+ irish: ['ga'],
279
+ russian: ['ru', 'uk'],
280
+ scottish: ['gd'],
281
+ spanish: ['pt-PT', 'it', 'es'],
282
+ welsh: ['cy']
283
+ };
284
+
285
+ /**
286
+ * Different pluralisation rule sets
287
+ *
288
+ * Returns the appropriate suffix for the plural form associated with `n`.
289
+ * Possible suffixes: 'zero', 'one', 'two', 'few', 'many', 'other' (the actual
290
+ * meaning of each differs per locale). 'other' should always exist, even in
291
+ * languages without plurals, such as Chinese.
292
+ * {@link https://cldr.unicode.org/index/cldr-spec/plural-rules}
293
+ *
294
+ * The count must be a positive integer. Negative numbers and decimals aren't accounted for
295
+ *
296
+ * @type {Object<string, function(number): PluralRule>}
297
+ */
298
+ I18n.pluralRules = {
299
+ arabic: function (n) {
300
+ if (n === 0) { return 'zero' }
301
+ if (n === 1) { return 'one' }
302
+ if (n === 2) { return 'two' }
303
+ if (n % 100 >= 3 && n % 100 <= 10) { return 'few' }
304
+ if (n % 100 >= 11 && n % 100 <= 99) { return 'many' }
305
+ return 'other'
306
+ },
307
+ chinese: function () {
308
+ return 'other'
309
+ },
310
+ french: function (n) {
311
+ return n === 0 || n === 1 ? 'one' : 'other'
312
+ },
313
+ german: function (n) {
314
+ return n === 1 ? 'one' : 'other'
315
+ },
316
+ irish: function (n) {
317
+ if (n === 1) { return 'one' }
318
+ if (n === 2) { return 'two' }
319
+ if (n >= 3 && n <= 6) { return 'few' }
320
+ if (n >= 7 && n <= 10) { return 'many' }
321
+ return 'other'
322
+ },
323
+ russian: function (n) {
324
+ var lastTwo = n % 100;
325
+ var last = lastTwo % 10;
326
+ if (last === 1 && lastTwo !== 11) { return 'one' }
327
+ if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) { return 'few' }
328
+ if (last === 0 || (last >= 5 && last <= 9) || (lastTwo >= 11 && lastTwo <= 14)) { return 'many' }
329
+ // Note: The 'other' suffix is only used by decimal numbers in Russian.
330
+ // We don't anticipate it being used, but it's here for consistency.
331
+ return 'other'
332
+ },
333
+ scottish: function (n) {
334
+ if (n === 1 || n === 11) { return 'one' }
335
+ if (n === 2 || n === 12) { return 'two' }
336
+ if ((n >= 3 && n <= 10) || (n >= 13 && n <= 19)) { return 'few' }
337
+ return 'other'
338
+ },
339
+ spanish: function (n) {
340
+ if (n === 1) { return 'one' }
341
+ if (n % 1000000 === 0 && n !== 0) { return 'many' }
342
+ return 'other'
343
+ },
344
+ welsh: function (n) {
345
+ if (n === 0) { return 'zero' }
346
+ if (n === 1) { return 'one' }
347
+ if (n === 2) { return 'two' }
348
+ if (n === 3) { return 'few' }
349
+ if (n === 6) { return 'many' }
350
+ return 'other'
351
+ }
352
+ };
353
+
354
+ /**
355
+ * Supported languages for plural rules
356
+ *
357
+ * @typedef {'arabic' | 'chinese' | 'french' | 'german' | 'irish' | 'russian' | 'scottish' | 'spanish' | 'welsh'} PluralRuleName
358
+ */
359
+
360
+ /**
361
+ * Plural rule category mnemonic tags
362
+ *
363
+ * @typedef {'zero' | 'one' | 'two' | 'few' | 'many' | 'other'} PluralRule
364
+ */
365
+
366
+ /**
367
+ * Translated message by plural rule they correspond to.
368
+ *
369
+ * Allows to group pluralised messages under a single key when passing
370
+ * translations to a component's constructor
371
+ *
372
+ * @typedef {object} TranslationPluralForms
373
+ * @property {string} [other] - General plural form
374
+ * @property {string} [zero] - Plural form used with 0
375
+ * @property {string} [one] - Plural form used with 1
376
+ * @property {string} [two] - Plural form used with 2
377
+ * @property {string} [few] - Plural form used for a few
378
+ * @property {string} [many] - Plural form used for many
379
+ */
380
+
381
+ /**
382
+ * Translated messages (flattened)
383
+ *
384
+ * @private
385
+ * @typedef {Object<string, string> | {}} TranslationsFlattened
386
+ */
387
+
388
+ exports.I18n = I18n;
389
+
390
+ })));
@@ -29,19 +29,12 @@
29
29
  // margins, but unfortunately the support isn't there (yet) and @supports
30
30
  // doesn't play nicely with it
31
31
  // (https://github.com/w3c/csswg-drafts/issues/3559)
32
- display: -webkit-box;
33
- display: -webkit-flex;
34
32
  display: -ms-flexbox;
35
33
  display: flex;
36
- -webkit-box-orient: vertical;
37
- -webkit-box-direction: normal;
38
- -webkit-flex-direction: column;
39
- -ms-flex-direction: column;
40
- flex-direction: column;
41
- -webkit-box-align: center;
42
- -webkit-align-items: center;
43
- -ms-flex-align: center;
44
- align-items: center;
34
+ -ms-flex-direction: column;
35
+ flex-direction: column;
36
+ -ms-flex-align: center;
37
+ align-items: center;
45
38
 
46
39
  // Give links within the button group the same font-size and line-height
47
40
  // as buttons.
@@ -71,22 +64,13 @@
71
64
  // Cancel out the column gap for the last item in each row
72
65
  margin-right: ($horizontal-gap * -1);
73
66
 
74
- -webkit-box-orient: horizontal;
67
+ -ms-flex-direction: row;
75
68
 
76
- -webkit-box-direction: normal;
77
-
78
- -webkit-flex-direction: row;
79
-
80
- -ms-flex-direction: row;
81
-
82
- flex-direction: row;
83
- -webkit-flex-wrap: wrap;
84
- -ms-flex-wrap: wrap;
85
- flex-wrap: wrap;
86
- -webkit-box-align: baseline;
87
- -webkit-align-items: baseline;
88
- -ms-flex-align: baseline;
89
- align-items: baseline;
69
+ flex-direction: row;
70
+ -ms-flex-wrap: wrap;
71
+ flex-wrap: wrap;
72
+ -ms-flex-align: baseline;
73
+ align-items: baseline;
90
74
 
91
75
  .govuk-button,
92
76
  .govuk-link {
@@ -11,7 +11,7 @@
11
11
  // Prevent automatic text sizing, as we already cater for small devices and
12
12
  // would like the browser to stay on 100% text zoom by default.
13
13
  -webkit-text-size-adjust: 100%;
14
- -ms-text-size-adjust: 100%;
14
+ -moz-text-size-adjust: 100%;
15
15
  text-size-adjust: 100%;
16
16
 
17
17
  // Force the scrollbar to always display in IE, to prevent horizontal page
@@ -28,9 +28,7 @@
28
28
 
29
29
  // Respect 'display cutout' safe area (avoids notches and rounded corners)
30
30
  @supports (margin: unquote("max(calc(0px))")) {
31
- $gutter-safe-area-right: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
32
31
  $gutter-safe-area-right: calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
33
- $gutter-safe-area-left: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
34
32
  $gutter-safe-area-left: calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
35
33
 
36
34
  // Use max() to pick largest margin, default or with safe area
@@ -46,9 +44,7 @@
46
44
 
47
45
  // Respect 'display cutout' safe area (avoids notches and rounded corners)
48
46
  @supports (margin: unquote("max(calc(0px))")) {
49
- $gutter-safe-area-right: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
50
47
  $gutter-safe-area-right: calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
51
- $gutter-safe-area-left: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
52
48
  $gutter-safe-area-left: calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
53
49
 
54
50
  // Use max() to pick largest margin, default or with safe area