defra_ruby_template 6.4.0 → 6.6.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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +73 -19
  3. data/Rakefile +10 -33
  4. data/lib/defra_ruby_template/version.rb +1 -1
  5. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +202 -137
  6. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js.map +1 -1
  7. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +202 -137
  8. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs.map +1 -1
  9. data/node_modules/govuk-frontend/dist/govuk/common/closest-attribute-value.mjs.map +1 -1
  10. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +5 -1
  11. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs.map +1 -1
  12. data/node_modules/govuk-frontend/dist/govuk/common/create-element.mjs +13 -0
  13. data/node_modules/govuk-frontend/dist/govuk/common/create-element.mjs.map +1 -0
  14. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  15. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs.map +1 -1
  16. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs.map +1 -1
  17. data/node_modules/govuk-frontend/dist/govuk/component.mjs +2 -1
  18. data/node_modules/govuk-frontend/dist/govuk/component.mjs.map +1 -1
  19. data/node_modules/govuk-frontend/dist/govuk/components/_index.import.scss +2 -0
  20. data/node_modules/govuk-frontend/dist/govuk/components/_index.scss +2 -0
  21. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +87 -62
  22. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js.map +1 -1
  23. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +87 -62
  24. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs.map +1 -1
  25. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +60 -56
  26. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs.map +1 -1
  27. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +17 -6
  28. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js.map +1 -1
  29. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +17 -6
  30. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs.map +1 -1
  31. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs.map +1 -1
  32. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +90 -32
  33. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js.map +1 -1
  34. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +90 -32
  35. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs.map +1 -1
  36. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +64 -27
  37. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs.map +1 -1
  38. data/node_modules/govuk-frontend/dist/govuk/components/character-count/fixtures.json +173 -6
  39. data/node_modules/govuk-frontend/dist/govuk/components/character-count/macro-options.json +13 -6
  40. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters-and-error-message.html +12 -0
  41. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters-and-threshold.html +9 -0
  42. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters-and-value.html +9 -0
  43. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters.html +9 -0
  44. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-length.html +9 -0
  45. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words-and-error-message.html +12 -0
  46. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words-and-threshold.html +9 -0
  47. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words-and-value.html +9 -0
  48. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words.html +9 -0
  49. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-maxwords.html +9 -0
  50. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template.njk +10 -3
  51. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +12 -5
  52. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js.map +1 -1
  53. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +12 -5
  54. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs.map +1 -1
  55. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs.map +1 -1
  56. data/node_modules/govuk-frontend/dist/govuk/components/cookie-banner/_mixin.scss +6 -0
  57. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +17 -6
  58. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js.map +1 -1
  59. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +17 -6
  60. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs.map +1 -1
  61. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs.map +1 -1
  62. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +43 -18
  63. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js.map +1 -1
  64. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +43 -18
  65. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs.map +1 -1
  66. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +16 -12
  67. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs.map +1 -1
  68. data/node_modules/govuk-frontend/dist/govuk/components/feedback/README.md +15 -0
  69. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_feedback.import.scss +6 -0
  70. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.import.scss +8 -0
  71. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.scss +5 -0
  72. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_mixin.scss +48 -0
  73. data/node_modules/govuk-frontend/dist/govuk/components/feedback/fixtures.json +95 -0
  74. data/node_modules/govuk-frontend/dist/govuk/components/feedback/macro-options.json +50 -0
  75. data/node_modules/govuk-frontend/dist/govuk/components/feedback/macro.njk +3 -0
  76. data/node_modules/govuk-frontend/dist/govuk/components/feedback/template-default.html +12 -0
  77. data/node_modules/govuk-frontend/dist/govuk/components/feedback/template-silly-example.html +19 -0
  78. data/node_modules/govuk-frontend/dist/govuk/components/feedback/template.njk +24 -0
  79. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +54 -30
  80. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js.map +1 -1
  81. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +54 -30
  82. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs.map +1 -1
  83. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +27 -24
  84. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs.map +1 -1
  85. data/node_modules/govuk-frontend/dist/govuk/components/footer/_mixin.scss +6 -0
  86. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/README.md +15 -0
  87. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.import.scss +8 -0
  88. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.scss +6 -0
  89. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_language-navigation.import.scss +6 -0
  90. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_mixin.scss +68 -0
  91. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/fixtures.json +482 -0
  92. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/macro-options.json +88 -0
  93. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/macro.njk +3 -0
  94. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-default.html +12 -0
  95. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-inverse.html +12 -0
  96. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-language-description.html +12 -0
  97. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-large-amount-of-multiple-languages.html +99 -0
  98. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-mixed-text-directions.html +12 -0
  99. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-multiple-languages.html +24 -0
  100. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-translated-navigation-label.html +12 -0
  101. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template.njk +33 -0
  102. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +17 -6
  103. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js.map +1 -1
  104. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +17 -6
  105. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs.map +1 -1
  106. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs.map +1 -1
  107. data/node_modules/govuk-frontend/dist/govuk/components/panel/fixtures.json +13 -11
  108. data/node_modules/govuk-frontend/dist/govuk/components/panel/template-interruption-with-headings-content-and-lists.html +6 -1
  109. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +32 -9
  110. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js.map +1 -1
  111. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +32 -9
  112. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs.map +1 -1
  113. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +5 -3
  114. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs.map +1 -1
  115. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +12 -5
  116. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js.map +1 -1
  117. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +12 -5
  118. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs.map +1 -1
  119. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs.map +1 -1
  120. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_mixin.scss +48 -3
  121. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/fixtures.json +121 -0
  122. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/macro-options.json +20 -0
  123. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +12 -5
  124. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js.map +1 -1
  125. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +12 -5
  126. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs.map +1 -1
  127. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs.map +1 -1
  128. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-inverse-with-language-navigation.html +72 -0
  129. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-inline-end-slot.html +33 -0
  130. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-language-navigation.html +62 -0
  131. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-right-aligned-language-navigation.html +62 -0
  132. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template.njk +8 -3
  133. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +14 -6
  134. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js.map +1 -1
  135. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +14 -6
  136. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs.map +1 -1
  137. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +2 -1
  138. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs.map +1 -1
  139. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +12 -5
  140. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js.map +1 -1
  141. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +12 -5
  142. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs.map +1 -1
  143. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs.map +1 -1
  144. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_frontend-version.mixin.scss +1 -1
  145. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_functional-colours.mixin.scss +1 -0
  146. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +8 -5
  147. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs.map +1 -1
  148. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css +2 -2
  149. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css.map +1 -1
  150. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  151. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js.map +1 -1
  152. data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +1 -1
  153. data/node_modules/govuk-frontend/dist/govuk/i18n.mjs.map +1 -1
  154. data/node_modules/govuk-frontend/dist/govuk/init.mjs +8 -8
  155. data/node_modules/govuk-frontend/dist/govuk/init.mjs.map +1 -1
  156. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +16 -2
  157. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +9 -1
  158. data/node_modules/govuk-frontend/package.json +9 -7
  159. data/vendor/assets/javascripts/defra_ruby_template.js +202 -137
  160. data/vendor/assets/stylesheets/components/_index.import.scss +2 -0
  161. data/vendor/assets/stylesheets/components/_index.scss +2 -0
  162. data/vendor/assets/stylesheets/components/cookie-banner/_mixin.scss +6 -0
  163. data/vendor/assets/stylesheets/components/feedback/_feedback.import.scss +6 -0
  164. data/vendor/assets/stylesheets/components/feedback/_index.import.scss +8 -0
  165. data/vendor/assets/stylesheets/components/feedback/_index.scss +5 -0
  166. data/vendor/assets/stylesheets/components/feedback/_mixin.scss +48 -0
  167. data/vendor/assets/stylesheets/components/footer/_mixin.scss +6 -0
  168. data/vendor/assets/stylesheets/components/language-navigation/_index.import.scss +8 -0
  169. data/vendor/assets/stylesheets/components/language-navigation/_index.scss +6 -0
  170. data/vendor/assets/stylesheets/components/language-navigation/_language-navigation.import.scss +6 -0
  171. data/vendor/assets/stylesheets/components/language-navigation/_mixin.scss +68 -0
  172. data/vendor/assets/stylesheets/components/service-navigation/_mixin.scss +48 -3
  173. data/vendor/assets/stylesheets/custom-properties/_frontend-version.mixin.scss +1 -1
  174. data/vendor/assets/stylesheets/custom-properties/_functional-colours.mixin.scss +1 -0
  175. data/vendor/assets/stylesheets/defra_ruby_template.scss +8 -30
  176. data/vendor/assets/stylesheets/govuk-frontend.min.css +2 -2
  177. data/vendor/assets/stylesheets/helpers/_colour.scss +1 -1
  178. data/vendor/assets/stylesheets/settings/_colours-organisations.scss +16 -2
  179. metadata +53 -3
  180. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-word-count.html +0 -9
@@ -28,6 +28,9 @@ function isArray(option) {
28
28
  function isObject(option) {
29
29
  return !!option && typeof option === 'object' && !isArray(option);
30
30
  }
31
+ function isScope($scope) {
32
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
33
+ }
31
34
  function formatErrorMessage(Component, message) {
32
35
  return `${Component.moduleName}: ${message}`;
33
36
  }
@@ -46,11 +49,14 @@ class SupportError extends GOVUKFrontendError {
46
49
  /**
47
50
  * Checks if GOV.UK Frontend is supported on this page
48
51
  *
49
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
52
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
50
53
  */
51
- constructor($scope = document.body) {
52
- const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
53
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
54
+ constructor(scopeOrMessage = document.body) {
55
+ let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
56
+ if (!isScope(scopeOrMessage)) {
57
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
58
+ }
59
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
54
60
  this.name = 'SupportError';
55
61
  }
56
62
  }
@@ -91,6 +97,7 @@ class InitError extends GOVUKFrontendError {
91
97
  * @import { ComponentWithModuleName } from '../common/index.mjs'
92
98
  */
93
99
 
100
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
94
101
  class Component {
95
102
  /**
96
103
  * Returns the root element of the component
@@ -144,7 +151,7 @@ class Component {
144
151
  /**
145
152
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
146
153
  */
147
- Component.elementType = HTMLElement;
154
+ Component.elementType = _self.HTMLElement;
148
155
 
149
156
  const configOverride = Symbol.for('configOverride');
150
157
  class ConfigurableComponent extends Component {
@@ -169,10 +176,14 @@ class ConfigurableComponent extends Component {
169
176
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
170
177
  }
171
178
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
172
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
179
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
180
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
173
181
  }
174
182
  }
175
183
  function normaliseString(value, property) {
184
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
185
+ return;
186
+ }
176
187
  const trimmedValue = value ? value.trim() : '';
177
188
  let output;
178
189
  let outputType = property == null ? void 0 : property.type;
@@ -312,6 +323,17 @@ function extractConfigByNamespace(schema, dataset, namespace) {
312
323
  * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
313
324
  */
314
325
 
326
+ function createElement(tagName, attributes = {}, children = []) {
327
+ const $element = document.createElement(tagName);
328
+ Object.entries(attributes).forEach(([name, value]) => {
329
+ $element.setAttribute(name, value);
330
+ });
331
+ for (const child of children) {
332
+ $element.append(child);
333
+ }
334
+ return $element;
335
+ }
336
+
315
337
  class I18n {
316
338
  constructor(translations = {}, config = {}) {
317
339
  var _config$locale;
@@ -402,6 +424,14 @@ class CharacterCount extends ConfigurableComponent {
402
424
  maxwords: undefined
403
425
  };
404
426
  }
427
+ if ('maxwords' in datasetConfig || this.config.maxwords !== undefined) {
428
+ console.warn(formatErrorMessage(CharacterCount, 'Option `maxwords` is deprecated. Use `maxlength` with `countType: "words"` instead.'));
429
+ if (!('maxlength' in datasetConfig)) {
430
+ var _datasetConfig$maxwor;
431
+ configOverrides.maxlength = (_datasetConfig$maxwor = datasetConfig.maxwords) != null ? _datasetConfig$maxwor : this.config.maxwords;
432
+ configOverrides.countType = 'words';
433
+ }
434
+ }
405
435
  return configOverrides;
406
436
  }
407
437
 
@@ -410,10 +440,11 @@ class CharacterCount extends ConfigurableComponent {
410
440
  * @param {CharacterCountConfig} [config] - Character count config
411
441
  */
412
442
  constructor($root, config = {}) {
413
- var _ref, _this$config$maxwords;
443
+ var _this$config$maxlengt;
414
444
  super($root, config);
415
445
  this.$textarea = void 0;
416
446
  this.count = 0;
447
+ this.segmenter = null;
417
448
  this.$visibleCountMessage = void 0;
418
449
  this.$screenReaderCountMessage = void 0;
419
450
  this.lastInputTimestamp = null;
@@ -437,7 +468,15 @@ class CharacterCount extends ConfigurableComponent {
437
468
  this.i18n = new I18n(this.config.i18n, {
438
469
  locale: closestAttributeValue(this.$root, 'lang')
439
470
  });
440
- this.maxLength = (_ref = (_this$config$maxwords = this.config.maxwords) != null ? _this$config$maxwords : this.config.maxlength) != null ? _ref : Infinity;
471
+ if (this.config.countType === 'characters' || this.config.countType === 'words' && this.config.maxwords === undefined) {
472
+ if (!('Segmenter' in Intl)) {
473
+ throw new SupportError(formatErrorMessage(CharacterCount, 'Support for "Intl.Segmenter" required'));
474
+ }
475
+ this.segmenter = new Intl.Segmenter(this.i18n.locale, {
476
+ granularity: this.config.countType === 'words' ? 'word' : 'grapheme'
477
+ });
478
+ }
479
+ this.maxLength = (_this$config$maxlengt = this.config.maxlength) != null ? _this$config$maxlengt : Infinity;
441
480
  this.$textarea = $textarea;
442
481
  const textareaDescriptionId = `${this.$textarea.id}-info`;
443
482
  const $textareaDescription = document.getElementById(textareaDescriptionId);
@@ -455,15 +494,16 @@ class CharacterCount extends ConfigurableComponent {
455
494
  });
456
495
  }
457
496
  this.$textarea.insertAdjacentElement('afterend', $textareaDescription);
458
- const $screenReaderCountMessage = document.createElement('div');
459
- $screenReaderCountMessage.className = 'govuk-character-count__sr-status govuk-visually-hidden';
460
- $screenReaderCountMessage.setAttribute('aria-live', 'polite');
497
+ const $screenReaderCountMessage = createElement('div', {
498
+ class: 'govuk-character-count__sr-status govuk-visually-hidden',
499
+ 'aria-live': 'polite'
500
+ });
461
501
  this.$screenReaderCountMessage = $screenReaderCountMessage;
462
502
  $textareaDescription.insertAdjacentElement('afterend', $screenReaderCountMessage);
463
- const $visibleCountMessage = document.createElement('div');
464
- $visibleCountMessage.className = $textareaDescription.className;
465
- $visibleCountMessage.classList.add('govuk-character-count__status');
466
- $visibleCountMessage.setAttribute('aria-hidden', 'true');
503
+ const $visibleCountMessage = createElement('div', {
504
+ class: `${$textareaDescription.className} govuk-character-count__status`,
505
+ 'aria-hidden': 'true'
506
+ });
467
507
  this.$visibleCountMessage = $visibleCountMessage;
468
508
  $textareaDescription.insertAdjacentElement('afterend', $visibleCountMessage);
469
509
  $textareaDescription.classList.add('govuk-visually-hidden');
@@ -531,26 +571,38 @@ class CharacterCount extends ConfigurableComponent {
531
571
  }
532
572
  updateCount() {
533
573
  const text = this.$textarea.value;
534
- if (this.config.maxwords) {
535
- var _text$match;
536
- const tokens = (_text$match = text.match(/\S+/g)) != null ? _text$match : [];
537
- this.count = tokens.length;
574
+ if (this.config.countType === 'characters') {
575
+ this.count = this.segmenter ? Array.from(this.segmenter.segment(text)).length : 0;
576
+ return;
577
+ }
578
+ if (this.config.countType === 'words') {
579
+ if (this.config.maxwords !== undefined) {
580
+ var _text$match$length, _text$match;
581
+ this.count = (_text$match$length = (_text$match = text.match(/\S+/g)) == null ? void 0 : _text$match.length) != null ? _text$match$length : 0;
582
+ return;
583
+ }
584
+ const segments = this.segmenter ? Array.from(this.segmenter.segment(text)) : [];
585
+ this.count = segments.filter(segment => segment.isWordLike).length;
538
586
  return;
539
587
  }
540
588
  this.count = text.length;
541
589
  }
542
590
  getCountMessage() {
543
591
  const remainingNumber = this.maxLength - this.count;
544
- const countType = this.config.maxwords ? 'words' : 'characters';
545
- return this.formatCountMessage(remainingNumber, countType);
592
+ return this.formatCountMessage(remainingNumber);
546
593
  }
547
594
  formatCountMessage(remainingNumber, countType) {
595
+ countType = countType != null ? countType : this.config.countType;
596
+ let translationKeyPrefix = 'characters';
597
+ let translationKeySuffix = remainingNumber < 0 ? 'OverLimit' : 'UnderLimit';
598
+ if (countType === 'words') {
599
+ translationKeyPrefix = 'words';
600
+ }
548
601
  if (remainingNumber === 0) {
549
- return this.i18n.t(`${countType}AtLimit`);
602
+ translationKeySuffix = 'AtLimit';
550
603
  }
551
- const translationKeySuffix = remainingNumber < 0 ? 'OverLimit' : 'UnderLimit';
552
- return this.i18n.t(`${countType}${translationKeySuffix}`, {
553
- count: Math.abs(remainingNumber)
604
+ return this.i18n.t(`${translationKeyPrefix}${translationKeySuffix}`, {
605
+ count: remainingNumber === 0 ? undefined : Math.abs(remainingNumber)
554
606
  });
555
607
  }
556
608
  isOverThreshold() {
@@ -569,13 +621,15 @@ class CharacterCount extends ConfigurableComponent {
569
621
  *
570
622
  * @see {@link CharacterCount.defaults}
571
623
  * @typedef {object} CharacterCountConfig
572
- * @property {number} [maxlength] - The maximum number of characters.
573
- * If maxwords is provided, the maxlength option will be ignored.
574
- * @property {number} [maxwords] - The maximum number of words. If maxwords is
575
- * provided, the maxlength option will be ignored.
624
+ * @property {number} [maxlength] - The maximum number of characters (or words
625
+ * if `countType` is set to `"words"`).
626
+ * @property {number} [maxwords] - Deprecated. Use `maxlength` and
627
+ * `countType: "words"` instead.
576
628
  * @property {number} [threshold=0] - The percentage value of the limit at
577
629
  * which point the count message is displayed. If this attribute is set, the
578
630
  * count message will be hidden by default.
631
+ * @property {'characters' | 'length' | 'words'} [countType] - The count type
632
+ * (`"characters"`, `"length"` or `"words"`) used to count the text.
579
633
  * @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations
580
634
  */
581
635
 
@@ -621,9 +675,9 @@ class CharacterCount extends ConfigurableComponent {
621
675
  * @property {TranslationPluralForms} [textareaDescription] - Message made
622
676
  * available to assistive technologies, if none is already present in the
623
677
  * HTML, to describe that the component accepts only a limited amount of
624
- * content. It is visible on the page when JavaScript is unavailable. The
625
- * component will replace the `%{count}` placeholder with the value of the
626
- * `maxlength` or `maxwords` parameter.
678
+ * content. It is visible on the page if `countType` is not supported or
679
+ * JavaScript is unavailable. The component will replace the `%{count}`
680
+ * placeholder with the value of the `maxlength` parameter.
627
681
  */
628
682
 
629
683
  /**
@@ -633,6 +687,7 @@ class CharacterCount extends ConfigurableComponent {
633
687
  CharacterCount.moduleName = 'govuk-character-count';
634
688
  CharacterCount.defaults = Object.freeze({
635
689
  threshold: 0,
690
+ countType: 'length',
636
691
  i18n: {
637
692
  charactersUnderLimit: {
638
693
  one: 'You have %{count} character remaining',
@@ -670,6 +725,9 @@ CharacterCount.schema = Object.freeze({
670
725
  },
671
726
  threshold: {
672
727
  type: 'number'
728
+ },
729
+ countType: {
730
+ type: 'string'
673
731
  }
674
732
  },
675
733
  anyOf: [{