govuk_tech_docs 5.2.1 → 6.0.0.beta

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +59 -0
  3. data/.npmrc +1 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +19 -0
  6. data/README.md +13 -4
  7. data/example/config/tech-docs.yml +1 -1
  8. data/govuk_tech_docs.gemspec +2 -2
  9. data/lib/assets/stylesheets/_core.scss +1 -0
  10. data/lib/assets/stylesheets/_govuk_tech_docs.scss +13 -15
  11. data/lib/assets/stylesheets/modules/_app-pane.scss +3 -3
  12. data/lib/assets/stylesheets/modules/_page-review.scss +4 -4
  13. data/lib/assets/stylesheets/modules/_search.scss +3 -3
  14. data/lib/assets/stylesheets/modules/_service-navigation.scss +5 -0
  15. data/lib/assets/stylesheets/modules/_technical-documentation.scss +7 -7
  16. data/lib/assets/stylesheets/modules/_toc.scss +13 -13
  17. data/lib/assets/stylesheets/palette/_syntax-highlighting.scss +9 -7
  18. data/lib/govuk_tech_docs/meta_tags.rb +1 -1
  19. data/lib/govuk_tech_docs/version.rb +1 -1
  20. data/lib/source/layouts/_header.erb +2 -16
  21. data/lib/source/layouts/_service_navigation.erb +27 -0
  22. data/lib/source/layouts/core.erb +7 -7
  23. data/node_modules/govuk-frontend/dist/govuk/_base.scss +1 -0
  24. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +183 -300
  25. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +184 -300
  26. data/node_modules/govuk-frontend/dist/govuk/all.mjs +0 -1
  27. data/node_modules/govuk-frontend/dist/govuk/assets/images/favicon.ico +0 -0
  28. data/node_modules/govuk-frontend/dist/govuk/assets/images/favicon.svg +1 -1
  29. data/node_modules/govuk-frontend/dist/govuk/assets/images/govuk-icon-180.png +0 -0
  30. data/node_modules/govuk-frontend/dist/govuk/assets/images/govuk-icon-192.png +0 -0
  31. data/node_modules/govuk-frontend/dist/govuk/assets/images/govuk-icon-512.png +0 -0
  32. data/node_modules/govuk-frontend/dist/govuk/assets/images/govuk-opengraph-image.png +0 -0
  33. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +29 -2
  34. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  35. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +4 -10
  36. data/node_modules/govuk-frontend/dist/govuk/components/accordion/_index.scss +18 -15
  37. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +14 -137
  38. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +14 -137
  39. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +4 -4
  40. data/node_modules/govuk-frontend/dist/govuk/components/back-link/_index.scss +2 -2
  41. data/node_modules/govuk-frontend/dist/govuk/components/breadcrumbs/_index.scss +2 -2
  42. data/node_modules/govuk-frontend/dist/govuk/components/button/_index.scss +18 -21
  43. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +7 -5
  44. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +7 -5
  45. data/node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss +2 -2
  46. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +30 -143
  47. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +30 -143
  48. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +20 -10
  49. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/_index.scss +7 -6
  50. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +10 -5
  51. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +10 -5
  52. data/node_modules/govuk-frontend/dist/govuk/components/cookie-banner/_index.scss +2 -5
  53. data/node_modules/govuk-frontend/dist/govuk/components/date-input/_index.scss +5 -0
  54. data/node_modules/govuk-frontend/dist/govuk/components/details/_index.scss +6 -4
  55. data/node_modules/govuk-frontend/dist/govuk/components/error-message/_index.scss +1 -1
  56. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/_index.scss +4 -2
  57. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +8 -12
  58. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +8 -12
  59. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +2 -2
  60. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/_index.scss +1 -1
  61. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +10 -133
  62. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +10 -133
  63. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss +30 -38
  64. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +46 -140
  65. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +46 -140
  66. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +36 -7
  67. data/node_modules/govuk-frontend/dist/govuk/components/footer/_index.scss +30 -27
  68. data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss +89 -449
  69. data/node_modules/govuk-frontend/dist/govuk/components/hint/_index.scss +1 -1
  70. data/node_modules/govuk-frontend/dist/govuk/components/input/_index.scss +14 -20
  71. data/node_modules/govuk-frontend/dist/govuk/components/inset-text/_index.scss +2 -1
  72. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/_index.scss +10 -8
  73. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +7 -5
  74. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +7 -5
  75. data/node_modules/govuk-frontend/dist/govuk/components/pagination/_index.scss +16 -11
  76. data/node_modules/govuk-frontend/dist/govuk/components/panel/_index.scss +4 -4
  77. data/node_modules/govuk-frontend/dist/govuk/components/password-input/_index.scss +2 -2
  78. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +10 -133
  79. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +10 -133
  80. data/node_modules/govuk-frontend/dist/govuk/components/phase-banner/_index.scss +12 -6
  81. data/node_modules/govuk-frontend/dist/govuk/components/radios/_index.scss +8 -7
  82. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +10 -5
  83. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +10 -5
  84. data/node_modules/govuk-frontend/dist/govuk/components/select/_index.scss +6 -11
  85. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_index.scss +58 -74
  86. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +40 -7
  87. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +40 -7
  88. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs +30 -2
  89. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/_index.scss +8 -4
  90. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +12 -19
  91. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +12 -19
  92. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +3 -9
  93. data/node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss +25 -21
  94. data/node_modules/govuk-frontend/dist/govuk/components/table/_index.scss +7 -8
  95. data/node_modules/govuk-frontend/dist/govuk/components/tabs/_index.scss +9 -6
  96. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +12 -13
  97. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +12 -13
  98. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs +3 -3
  99. data/node_modules/govuk-frontend/dist/govuk/components/tag/_index.scss +66 -31
  100. data/node_modules/govuk-frontend/dist/govuk/components/task-list/_index.scss +7 -5
  101. data/node_modules/govuk-frontend/dist/govuk/components/textarea/_index.scss +5 -10
  102. data/node_modules/govuk-frontend/dist/govuk/components/warning-text/_index.scss +5 -4
  103. data/node_modules/govuk-frontend/dist/govuk/core/_index.scss +0 -1
  104. data/node_modules/govuk-frontend/dist/govuk/core/_lists.scss +2 -2
  105. data/node_modules/govuk-frontend/dist/govuk/core/_section-break.scss +2 -1
  106. data/node_modules/govuk-frontend/dist/govuk/core/_typography.scss +6 -20
  107. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_breakpoints.scss +17 -0
  108. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_frontend-version.scss +15 -0
  109. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_functional-colours.scss +17 -0
  110. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_index.scss +5 -0
  111. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +5 -3
  112. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  113. data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +187 -72
  114. data/node_modules/govuk-frontend/dist/govuk/helpers/_focused.scss +41 -6
  115. data/node_modules/govuk-frontend/dist/govuk/helpers/_grid.scss +1 -1
  116. data/node_modules/govuk-frontend/dist/govuk/helpers/_links.scss +24 -40
  117. data/node_modules/govuk-frontend/dist/govuk/helpers/_media-queries.scss +172 -33
  118. data/node_modules/govuk-frontend/dist/govuk/helpers/_spacing.scss +1 -1
  119. data/node_modules/govuk-frontend/dist/govuk/helpers/_typography.scss +6 -30
  120. data/node_modules/govuk-frontend/dist/govuk/helpers/_visually-hidden.scss +4 -1
  121. data/node_modules/govuk-frontend/dist/govuk/i18n.mjs +5 -128
  122. data/node_modules/govuk-frontend/dist/govuk/init.mjs +53 -45
  123. data/node_modules/govuk-frontend/dist/govuk/objects/_button-group.scss +1 -1
  124. data/node_modules/govuk-frontend/dist/govuk/objects/_form-group.scss +2 -1
  125. data/node_modules/govuk-frontend/dist/govuk/objects/_main-wrapper.scss +1 -1
  126. data/node_modules/govuk-frontend/dist/govuk/objects/_template.scss +3 -7
  127. data/node_modules/govuk-frontend/dist/govuk/objects/_width-container.scss +2 -2
  128. data/node_modules/govuk-frontend/dist/govuk/overrides/_display.scss +1 -1
  129. data/node_modules/govuk-frontend/dist/govuk/overrides/_typography.scss +0 -2
  130. data/node_modules/govuk-frontend/dist/govuk/overrides/_width.scss +5 -5
  131. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-applied.scss +3 -188
  132. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-functional.scss +366 -0
  133. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +9 -255
  134. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-palette.scss +117 -25
  135. data/node_modules/govuk-frontend/dist/govuk/settings/_custom-properties.scss +18 -0
  136. data/node_modules/govuk-frontend/dist/govuk/settings/_index.scss +3 -14
  137. data/node_modules/govuk-frontend/dist/govuk/settings/_media-queries.scss +0 -9
  138. data/node_modules/govuk-frontend/dist/govuk/settings/_typography-responsive.scss +12 -189
  139. data/node_modules/govuk-frontend/dist/govuk/tools/_index.scss +0 -1
  140. data/node_modules/govuk-frontend/dist/govuk/tools/_px-to-em.scss +4 -2
  141. data/node_modules/govuk-frontend/dist/govuk/tools/_px-to-rem.scss +2 -0
  142. data/package-lock.json +2461 -1150
  143. data/package.json +3 -3
  144. metadata +16 -30
  145. data/node_modules/govuk-frontend/dist/govuk/all.scss +0 -9
  146. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/favicon.ico +0 -0
  147. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/favicon.svg +0 -1
  148. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/govuk-crest.svg +0 -1
  149. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/govuk-icon-180.png +0 -0
  150. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/govuk-icon-192.png +0 -0
  151. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/govuk-icon-512.png +0 -0
  152. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/govuk-icon-mask.svg +0 -1
  153. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/images/govuk-opengraph-image.png +0 -0
  154. data/node_modules/govuk-frontend/dist/govuk/assets/rebrand/manifest.json +0 -39
  155. data/node_modules/govuk-frontend/dist/govuk/components/_all.scss +0 -10
  156. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +0 -233
  157. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +0 -225
  158. data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs +0 -89
  159. data/node_modules/govuk-frontend/dist/govuk/core/_all.scss +0 -10
  160. data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +0 -15
  161. data/node_modules/govuk-frontend/dist/govuk/helpers/_all.scss +0 -10
  162. data/node_modules/govuk-frontend/dist/govuk/objects/_all.scss +0 -10
  163. data/node_modules/govuk-frontend/dist/govuk/overrides/_all.scss +0 -9
  164. data/node_modules/govuk-frontend/dist/govuk/settings/_all.scss +0 -10
  165. data/node_modules/govuk-frontend/dist/govuk/tools/_all.scss +0 -10
  166. data/node_modules/govuk-frontend/dist/govuk/tools/_rebrand.scss +0 -65
  167. data/node_modules/govuk-frontend/dist/govuk/utilities/_all.scss +0 -10
  168. data/node_modules/govuk-frontend/dist/govuk/vendor/_sass-mq.scss +0 -349
  169. data/node_modules/govuk-frontend/dist/govuk-prototype-kit/functions.js +0 -25
@@ -41,9 +41,6 @@
41
41
  * @typedef ComponentWithModuleName
42
42
  * @property {string} moduleName - Name of the component
43
43
  */
44
- /**
45
- * @import { ObjectNested } from './configuration.mjs'
46
- */
47
44
 
48
45
  class GOVUKFrontendError extends Error {
49
46
  constructor(...args) {
@@ -72,7 +69,7 @@
72
69
  class ElementError extends GOVUKFrontendError {
73
70
  constructor(messageOrOptions) {
74
71
  let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
75
- if (typeof messageOrOptions === 'object') {
72
+ if (isObject(messageOrOptions)) {
76
73
  const {
77
74
  component,
78
75
  identifier,
@@ -81,7 +78,9 @@
81
78
  } = messageOrOptions;
82
79
  message = identifier;
83
80
  message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
84
- message = formatErrorMessage(component, message);
81
+ if (component) {
82
+ message = formatErrorMessage(component, message);
83
+ }
85
84
  }
86
85
  super(message);
87
86
  this.name = 'ElementError';
@@ -295,6 +294,9 @@
295
294
  * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
296
295
  * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
297
296
  */
297
+ /**
298
+ * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
299
+ */
298
300
 
299
301
  class I18n {
300
302
  constructor(translations = {}, config = {}) {
@@ -309,7 +311,7 @@
309
311
  throw new Error('i18n: lookup key missing');
310
312
  }
311
313
  let translation = this.translations[lookupKey];
312
- if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
314
+ if (typeof (options == null ? void 0 : options.count) === 'number' && isObject(translation)) {
313
315
  const translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
314
316
  if (translationPluralForm) {
315
317
  translation = translationPluralForm;
@@ -351,8 +353,8 @@
351
353
  return 'other';
352
354
  }
353
355
  const translation = this.translations[lookupKey];
354
- const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
355
- if (typeof translation === 'object') {
356
+ const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : 'other';
357
+ if (isObject(translation)) {
356
358
  if (preferredForm in translation) {
357
359
  return preferredForm;
358
360
  } else if ('other' in translation) {
@@ -362,132 +364,7 @@
362
364
  }
363
365
  throw new Error(`i18n: Plural form ".other" is required for "${this.locale}" locale`);
364
366
  }
365
- selectPluralFormUsingFallbackRules(count) {
366
- count = Math.abs(Math.floor(count));
367
- const ruleset = this.getPluralRulesForLocale();
368
- if (ruleset) {
369
- return I18n.pluralRules[ruleset](count);
370
- }
371
- return 'other';
372
- }
373
- getPluralRulesForLocale() {
374
- const localeShort = this.locale.split('-')[0];
375
- for (const pluralRule in I18n.pluralRulesMap) {
376
- const languages = I18n.pluralRulesMap[pluralRule];
377
- if (languages.includes(this.locale) || languages.includes(localeShort)) {
378
- return pluralRule;
379
- }
380
- }
381
- }
382
367
  }
383
- I18n.pluralRulesMap = {
384
- arabic: ['ar'],
385
- chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
386
- french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
387
- german: ['af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka', 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'],
388
- irish: ['ga'],
389
- russian: ['ru', 'uk'],
390
- scottish: ['gd'],
391
- spanish: ['pt-PT', 'it', 'es'],
392
- welsh: ['cy']
393
- };
394
- I18n.pluralRules = {
395
- arabic(n) {
396
- if (n === 0) {
397
- return 'zero';
398
- }
399
- if (n === 1) {
400
- return 'one';
401
- }
402
- if (n === 2) {
403
- return 'two';
404
- }
405
- if (n % 100 >= 3 && n % 100 <= 10) {
406
- return 'few';
407
- }
408
- if (n % 100 >= 11 && n % 100 <= 99) {
409
- return 'many';
410
- }
411
- return 'other';
412
- },
413
- chinese() {
414
- return 'other';
415
- },
416
- french(n) {
417
- return n === 0 || n === 1 ? 'one' : 'other';
418
- },
419
- german(n) {
420
- return n === 1 ? 'one' : 'other';
421
- },
422
- irish(n) {
423
- if (n === 1) {
424
- return 'one';
425
- }
426
- if (n === 2) {
427
- return 'two';
428
- }
429
- if (n >= 3 && n <= 6) {
430
- return 'few';
431
- }
432
- if (n >= 7 && n <= 10) {
433
- return 'many';
434
- }
435
- return 'other';
436
- },
437
- russian(n) {
438
- const lastTwo = n % 100;
439
- const last = lastTwo % 10;
440
- if (last === 1 && lastTwo !== 11) {
441
- return 'one';
442
- }
443
- if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
444
- return 'few';
445
- }
446
- if (last === 0 || last >= 5 && last <= 9 || lastTwo >= 11 && lastTwo <= 14) {
447
- return 'many';
448
- }
449
- return 'other';
450
- },
451
- scottish(n) {
452
- if (n === 1 || n === 11) {
453
- return 'one';
454
- }
455
- if (n === 2 || n === 12) {
456
- return 'two';
457
- }
458
- if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
459
- return 'few';
460
- }
461
- return 'other';
462
- },
463
- spanish(n) {
464
- if (n === 1) {
465
- return 'one';
466
- }
467
- if (n % 1000000 === 0 && n !== 0) {
468
- return 'many';
469
- }
470
- return 'other';
471
- },
472
- welsh(n) {
473
- if (n === 0) {
474
- return 'zero';
475
- }
476
- if (n === 1) {
477
- return 'one';
478
- }
479
- if (n === 2) {
480
- return 'two';
481
- }
482
- if (n === 3) {
483
- return 'few';
484
- }
485
- if (n === 6) {
486
- return 'many';
487
- }
488
- return 'other';
489
- }
490
- };
491
368
 
492
369
  /**
493
370
  * File upload component
@@ -520,7 +397,6 @@
520
397
  throw new ElementError(formatErrorMessage(FileUpload, 'File input (`<input type="file">`) attribute (`type`) is not `file`'));
521
398
  }
522
399
  this.$input = $input;
523
- this.$input.setAttribute('hidden', 'true');
524
400
  if (!this.$input.id) {
525
401
  throw new ElementError({
526
402
  component: FileUpload,
@@ -536,6 +412,7 @@
536
412
  $label.id = `${this.id}-label`;
537
413
  }
538
414
  this.$input.id = `${this.id}-input`;
415
+ this.$input.setAttribute('hidden', 'true');
539
416
  const $button = document.createElement('button');
540
417
  $button.classList.add('govuk-file-upload-button');
541
418
  $button.type = 'button';
@@ -602,7 +479,7 @@
602
479
  if (this.$button.disabled) return;
603
480
  if (event.target instanceof Node) {
604
481
  if (this.$root.contains(event.target)) {
605
- if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
482
+ if (event.dataTransfer && this.canDrop(event.dataTransfer)) {
606
483
  if (!this.$button.classList.contains('govuk-file-upload-button--dragging')) {
607
484
  this.showDraggingState();
608
485
  this.$announcements.innerText = this.i18n.t('enteredDropZone');
@@ -624,12 +501,30 @@
624
501
  }
625
502
  onDrop(event) {
626
503
  event.preventDefault();
627
- if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
504
+ if (event.dataTransfer && this.canFillInput(event.dataTransfer)) {
628
505
  this.$input.files = event.dataTransfer.files;
629
506
  this.$input.dispatchEvent(new CustomEvent('change'));
630
507
  this.hideDraggingState();
631
508
  }
632
509
  }
510
+ canFillInput(dataTransfer) {
511
+ return this.matchesInputCapacity(dataTransfer.files.length);
512
+ }
513
+ canDrop(dataTransfer) {
514
+ if (dataTransfer.items.length) {
515
+ return this.matchesInputCapacity(countFileItems(dataTransfer.items));
516
+ }
517
+ if (dataTransfer.types.length) {
518
+ return dataTransfer.types.includes('Files');
519
+ }
520
+ return true;
521
+ }
522
+ matchesInputCapacity(numberOfFiles) {
523
+ if (this.$input.multiple) {
524
+ return numberOfFiles > 0;
525
+ }
526
+ return numberOfFiles === 1;
527
+ }
633
528
  onChange() {
634
529
  const fileCount = this.$input.files.length;
635
530
  if (fileCount === 0) {
@@ -676,6 +571,13 @@
676
571
  this.$root.classList.toggle('govuk-drop-zone--disabled', this.$button.disabled);
677
572
  }
678
573
  }
574
+
575
+ /**
576
+ * Counts the number of `DataTransferItem` whose kind is `file`
577
+ *
578
+ * @param {DataTransferItemList} list - The list
579
+ * @returns {number} - The number of items whose kind is `file` in the list
580
+ */
679
581
  FileUpload.moduleName = 'govuk-file-upload';
680
582
  FileUpload.defaults = Object.freeze({
681
583
  i18n: {
@@ -697,10 +599,14 @@
697
599
  }
698
600
  }
699
601
  });
700
- function isContainingFiles(dataTransfer) {
701
- const hasNoTypesInfo = dataTransfer.types.length === 0;
702
- const isDraggingFiles = dataTransfer.types.some(type => type === 'Files');
703
- return hasNoTypesInfo || isDraggingFiles;
602
+ function countFileItems(list) {
603
+ let result = 0;
604
+ for (let i = 0; i < list.length; i++) {
605
+ if (list[i].kind === 'file') {
606
+ result++;
607
+ }
608
+ }
609
+ return result;
704
610
  }
705
611
 
706
612
  /**
@@ -35,9 +35,6 @@ function formatErrorMessage(Component, message) {
35
35
  * @typedef ComponentWithModuleName
36
36
  * @property {string} moduleName - Name of the component
37
37
  */
38
- /**
39
- * @import { ObjectNested } from './configuration.mjs'
40
- */
41
38
 
42
39
  class GOVUKFrontendError extends Error {
43
40
  constructor(...args) {
@@ -66,7 +63,7 @@ class ConfigError extends GOVUKFrontendError {
66
63
  class ElementError extends GOVUKFrontendError {
67
64
  constructor(messageOrOptions) {
68
65
  let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
69
- if (typeof messageOrOptions === 'object') {
66
+ if (isObject(messageOrOptions)) {
70
67
  const {
71
68
  component,
72
69
  identifier,
@@ -75,7 +72,9 @@ class ElementError extends GOVUKFrontendError {
75
72
  } = messageOrOptions;
76
73
  message = identifier;
77
74
  message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
78
- message = formatErrorMessage(component, message);
75
+ if (component) {
76
+ message = formatErrorMessage(component, message);
77
+ }
79
78
  }
80
79
  super(message);
81
80
  this.name = 'ElementError';
@@ -289,6 +288,9 @@ function extractConfigByNamespace(schema, dataset, namespace) {
289
288
  * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
290
289
  * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
291
290
  */
291
+ /**
292
+ * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
293
+ */
292
294
 
293
295
  class I18n {
294
296
  constructor(translations = {}, config = {}) {
@@ -303,7 +305,7 @@ class I18n {
303
305
  throw new Error('i18n: lookup key missing');
304
306
  }
305
307
  let translation = this.translations[lookupKey];
306
- if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
308
+ if (typeof (options == null ? void 0 : options.count) === 'number' && isObject(translation)) {
307
309
  const translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
308
310
  if (translationPluralForm) {
309
311
  translation = translationPluralForm;
@@ -345,8 +347,8 @@ class I18n {
345
347
  return 'other';
346
348
  }
347
349
  const translation = this.translations[lookupKey];
348
- const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
349
- if (typeof translation === 'object') {
350
+ const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : 'other';
351
+ if (isObject(translation)) {
350
352
  if (preferredForm in translation) {
351
353
  return preferredForm;
352
354
  } else if ('other' in translation) {
@@ -356,132 +358,7 @@ class I18n {
356
358
  }
357
359
  throw new Error(`i18n: Plural form ".other" is required for "${this.locale}" locale`);
358
360
  }
359
- selectPluralFormUsingFallbackRules(count) {
360
- count = Math.abs(Math.floor(count));
361
- const ruleset = this.getPluralRulesForLocale();
362
- if (ruleset) {
363
- return I18n.pluralRules[ruleset](count);
364
- }
365
- return 'other';
366
- }
367
- getPluralRulesForLocale() {
368
- const localeShort = this.locale.split('-')[0];
369
- for (const pluralRule in I18n.pluralRulesMap) {
370
- const languages = I18n.pluralRulesMap[pluralRule];
371
- if (languages.includes(this.locale) || languages.includes(localeShort)) {
372
- return pluralRule;
373
- }
374
- }
375
- }
376
361
  }
377
- I18n.pluralRulesMap = {
378
- arabic: ['ar'],
379
- chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
380
- french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
381
- german: ['af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka', 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'],
382
- irish: ['ga'],
383
- russian: ['ru', 'uk'],
384
- scottish: ['gd'],
385
- spanish: ['pt-PT', 'it', 'es'],
386
- welsh: ['cy']
387
- };
388
- I18n.pluralRules = {
389
- arabic(n) {
390
- if (n === 0) {
391
- return 'zero';
392
- }
393
- if (n === 1) {
394
- return 'one';
395
- }
396
- if (n === 2) {
397
- return 'two';
398
- }
399
- if (n % 100 >= 3 && n % 100 <= 10) {
400
- return 'few';
401
- }
402
- if (n % 100 >= 11 && n % 100 <= 99) {
403
- return 'many';
404
- }
405
- return 'other';
406
- },
407
- chinese() {
408
- return 'other';
409
- },
410
- french(n) {
411
- return n === 0 || n === 1 ? 'one' : 'other';
412
- },
413
- german(n) {
414
- return n === 1 ? 'one' : 'other';
415
- },
416
- irish(n) {
417
- if (n === 1) {
418
- return 'one';
419
- }
420
- if (n === 2) {
421
- return 'two';
422
- }
423
- if (n >= 3 && n <= 6) {
424
- return 'few';
425
- }
426
- if (n >= 7 && n <= 10) {
427
- return 'many';
428
- }
429
- return 'other';
430
- },
431
- russian(n) {
432
- const lastTwo = n % 100;
433
- const last = lastTwo % 10;
434
- if (last === 1 && lastTwo !== 11) {
435
- return 'one';
436
- }
437
- if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
438
- return 'few';
439
- }
440
- if (last === 0 || last >= 5 && last <= 9 || lastTwo >= 11 && lastTwo <= 14) {
441
- return 'many';
442
- }
443
- return 'other';
444
- },
445
- scottish(n) {
446
- if (n === 1 || n === 11) {
447
- return 'one';
448
- }
449
- if (n === 2 || n === 12) {
450
- return 'two';
451
- }
452
- if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
453
- return 'few';
454
- }
455
- return 'other';
456
- },
457
- spanish(n) {
458
- if (n === 1) {
459
- return 'one';
460
- }
461
- if (n % 1000000 === 0 && n !== 0) {
462
- return 'many';
463
- }
464
- return 'other';
465
- },
466
- welsh(n) {
467
- if (n === 0) {
468
- return 'zero';
469
- }
470
- if (n === 1) {
471
- return 'one';
472
- }
473
- if (n === 2) {
474
- return 'two';
475
- }
476
- if (n === 3) {
477
- return 'few';
478
- }
479
- if (n === 6) {
480
- return 'many';
481
- }
482
- return 'other';
483
- }
484
- };
485
362
 
486
363
  /**
487
364
  * File upload component
@@ -514,7 +391,6 @@ class FileUpload extends ConfigurableComponent {
514
391
  throw new ElementError(formatErrorMessage(FileUpload, 'File input (`<input type="file">`) attribute (`type`) is not `file`'));
515
392
  }
516
393
  this.$input = $input;
517
- this.$input.setAttribute('hidden', 'true');
518
394
  if (!this.$input.id) {
519
395
  throw new ElementError({
520
396
  component: FileUpload,
@@ -530,6 +406,7 @@ class FileUpload extends ConfigurableComponent {
530
406
  $label.id = `${this.id}-label`;
531
407
  }
532
408
  this.$input.id = `${this.id}-input`;
409
+ this.$input.setAttribute('hidden', 'true');
533
410
  const $button = document.createElement('button');
534
411
  $button.classList.add('govuk-file-upload-button');
535
412
  $button.type = 'button';
@@ -596,7 +473,7 @@ class FileUpload extends ConfigurableComponent {
596
473
  if (this.$button.disabled) return;
597
474
  if (event.target instanceof Node) {
598
475
  if (this.$root.contains(event.target)) {
599
- if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
476
+ if (event.dataTransfer && this.canDrop(event.dataTransfer)) {
600
477
  if (!this.$button.classList.contains('govuk-file-upload-button--dragging')) {
601
478
  this.showDraggingState();
602
479
  this.$announcements.innerText = this.i18n.t('enteredDropZone');
@@ -618,12 +495,30 @@ class FileUpload extends ConfigurableComponent {
618
495
  }
619
496
  onDrop(event) {
620
497
  event.preventDefault();
621
- if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
498
+ if (event.dataTransfer && this.canFillInput(event.dataTransfer)) {
622
499
  this.$input.files = event.dataTransfer.files;
623
500
  this.$input.dispatchEvent(new CustomEvent('change'));
624
501
  this.hideDraggingState();
625
502
  }
626
503
  }
504
+ canFillInput(dataTransfer) {
505
+ return this.matchesInputCapacity(dataTransfer.files.length);
506
+ }
507
+ canDrop(dataTransfer) {
508
+ if (dataTransfer.items.length) {
509
+ return this.matchesInputCapacity(countFileItems(dataTransfer.items));
510
+ }
511
+ if (dataTransfer.types.length) {
512
+ return dataTransfer.types.includes('Files');
513
+ }
514
+ return true;
515
+ }
516
+ matchesInputCapacity(numberOfFiles) {
517
+ if (this.$input.multiple) {
518
+ return numberOfFiles > 0;
519
+ }
520
+ return numberOfFiles === 1;
521
+ }
627
522
  onChange() {
628
523
  const fileCount = this.$input.files.length;
629
524
  if (fileCount === 0) {
@@ -670,6 +565,13 @@ class FileUpload extends ConfigurableComponent {
670
565
  this.$root.classList.toggle('govuk-drop-zone--disabled', this.$button.disabled);
671
566
  }
672
567
  }
568
+
569
+ /**
570
+ * Counts the number of `DataTransferItem` whose kind is `file`
571
+ *
572
+ * @param {DataTransferItemList} list - The list
573
+ * @returns {number} - The number of items whose kind is `file` in the list
574
+ */
673
575
  FileUpload.moduleName = 'govuk-file-upload';
674
576
  FileUpload.defaults = Object.freeze({
675
577
  i18n: {
@@ -691,10 +593,14 @@ FileUpload.schema = Object.freeze({
691
593
  }
692
594
  }
693
595
  });
694
- function isContainingFiles(dataTransfer) {
695
- const hasNoTypesInfo = dataTransfer.types.length === 0;
696
- const isDraggingFiles = dataTransfer.types.some(type => type === 'Files');
697
- return hasNoTypesInfo || isDraggingFiles;
596
+ function countFileItems(list) {
597
+ let result = 0;
598
+ for (let i = 0; i < list.length; i++) {
599
+ if (list[i].kind === 'file') {
600
+ result++;
601
+ }
602
+ }
603
+ return result;
698
604
  }
699
605
 
700
606
  /**
@@ -35,7 +35,6 @@ class FileUpload extends ConfigurableComponent {
35
35
  throw new ElementError(formatErrorMessage(FileUpload, 'File input (`<input type="file">`) attribute (`type`) is not `file`'));
36
36
  }
37
37
  this.$input = $input;
38
- this.$input.setAttribute('hidden', 'true');
39
38
  if (!this.$input.id) {
40
39
  throw new ElementError({
41
40
  component: FileUpload,
@@ -51,6 +50,7 @@ class FileUpload extends ConfigurableComponent {
51
50
  $label.id = `${this.id}-label`;
52
51
  }
53
52
  this.$input.id = `${this.id}-input`;
53
+ this.$input.setAttribute('hidden', 'true');
54
54
  const $button = document.createElement('button');
55
55
  $button.classList.add('govuk-file-upload-button');
56
56
  $button.type = 'button';
@@ -117,7 +117,7 @@ class FileUpload extends ConfigurableComponent {
117
117
  if (this.$button.disabled) return;
118
118
  if (event.target instanceof Node) {
119
119
  if (this.$root.contains(event.target)) {
120
- if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
120
+ if (event.dataTransfer && this.canDrop(event.dataTransfer)) {
121
121
  if (!this.$button.classList.contains('govuk-file-upload-button--dragging')) {
122
122
  this.showDraggingState();
123
123
  this.$announcements.innerText = this.i18n.t('enteredDropZone');
@@ -139,12 +139,30 @@ class FileUpload extends ConfigurableComponent {
139
139
  }
140
140
  onDrop(event) {
141
141
  event.preventDefault();
142
- if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
142
+ if (event.dataTransfer && this.canFillInput(event.dataTransfer)) {
143
143
  this.$input.files = event.dataTransfer.files;
144
144
  this.$input.dispatchEvent(new CustomEvent('change'));
145
145
  this.hideDraggingState();
146
146
  }
147
147
  }
148
+ canFillInput(dataTransfer) {
149
+ return this.matchesInputCapacity(dataTransfer.files.length);
150
+ }
151
+ canDrop(dataTransfer) {
152
+ if (dataTransfer.items.length) {
153
+ return this.matchesInputCapacity(countFileItems(dataTransfer.items));
154
+ }
155
+ if (dataTransfer.types.length) {
156
+ return dataTransfer.types.includes('Files');
157
+ }
158
+ return true;
159
+ }
160
+ matchesInputCapacity(numberOfFiles) {
161
+ if (this.$input.multiple) {
162
+ return numberOfFiles > 0;
163
+ }
164
+ return numberOfFiles === 1;
165
+ }
148
166
  onChange() {
149
167
  const fileCount = this.$input.files.length;
150
168
  if (fileCount === 0) {
@@ -191,6 +209,13 @@ class FileUpload extends ConfigurableComponent {
191
209
  this.$root.classList.toggle('govuk-drop-zone--disabled', this.$button.disabled);
192
210
  }
193
211
  }
212
+
213
+ /**
214
+ * Counts the number of `DataTransferItem` whose kind is `file`
215
+ *
216
+ * @param {DataTransferItemList} list - The list
217
+ * @returns {number} - The number of items whose kind is `file` in the list
218
+ */
194
219
  FileUpload.moduleName = 'govuk-file-upload';
195
220
  FileUpload.defaults = Object.freeze({
196
221
  i18n: {
@@ -212,10 +237,14 @@ FileUpload.schema = Object.freeze({
212
237
  }
213
238
  }
214
239
  });
215
- function isContainingFiles(dataTransfer) {
216
- const hasNoTypesInfo = dataTransfer.types.length === 0;
217
- const isDraggingFiles = dataTransfer.types.some(type => type === 'Files');
218
- return hasNoTypesInfo || isDraggingFiles;
240
+ function countFileItems(list) {
241
+ let result = 0;
242
+ for (let i = 0; i < list.length; i++) {
243
+ if (list[i].kind === 'file') {
244
+ result++;
245
+ }
246
+ }
247
+ return result;
219
248
  }
220
249
 
221
250
  /**