design_system 0.10.0 → 0.12.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 (292) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/components/_index.scss +36 -20
  3. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/action-link/_action-link.scss +3 -0
  4. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/action-link/_index.scss +84 -0
  5. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/back-link/_back-link.scss +3 -0
  6. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/back-link/_index.scss +56 -0
  7. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/breadcrumb/_breadcrumb.scss +3 -0
  8. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/breadcrumb/_index.scss +103 -0
  9. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/button/_button.scss +3 -0
  10. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/button/_index.scss +207 -0
  11. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/card/_card.scss +3 -0
  12. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/card/_index.scss +526 -0
  13. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/character-count/_character-count.scss +3 -0
  14. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/character-count/_index.scss +54 -0
  15. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/checkboxes/_checkboxes.scss +3 -0
  16. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/checkboxes/_index.scss +337 -0
  17. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/contents-list/_contents-list.scss +3 -0
  18. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/contents-list/_index.scss +32 -0
  19. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/date-input/_date-input.scss +3 -0
  20. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/date-input/_index.scss +40 -0
  21. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/details/_details.scss +3 -0
  22. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/details/_index.scss +374 -0
  23. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/do-dont-list/_do-dont-list.scss +3 -0
  24. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/do-dont-list/_index.scss +37 -0
  25. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/error-message/_error-message.scss +3 -0
  26. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/error-message/_index.scss +22 -0
  27. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/error-summary/_error-summary.scss +3 -0
  28. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/error-summary/_index.scss +75 -0
  29. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/fieldset/_fieldset.scss +3 -0
  30. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/fieldset/_index.scss +81 -0
  31. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/file-upload/_file-upload.scss +3 -0
  32. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/file-upload/_index.scss +251 -0
  33. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/footer/_footer.scss +3 -0
  34. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/footer/_index.scss +64 -0
  35. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/header/_header.scss +3 -0
  36. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/header/_index.scss +783 -0
  37. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/hero/_hero.scss +3 -0
  38. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/hero/_index.scss +205 -0
  39. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/hint/_hint.scss +3 -0
  40. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/hint/_index.scss +53 -0
  41. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/images/_images.scss +3 -0
  42. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/images/_index.scss +53 -0
  43. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/input/_index.scss +184 -0
  44. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/input/_input.scss +3 -0
  45. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/inset-text/_index.scss +34 -0
  46. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/inset-text/_inset-text.scss +3 -0
  47. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/label/_index.scss +53 -0
  48. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/label/_label.scss +3 -0
  49. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/notification-banner/_index.scss +100 -0
  50. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/notification-banner/_notification-banner.scss +3 -0
  51. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/pagination/_index.scss +261 -0
  52. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/pagination/_pagination.scss +3 -0
  53. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/panel/_index.scss +99 -0
  54. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/panel/_panel.scss +3 -0
  55. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/password-input/_index.scss +37 -0
  56. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/password-input/_password-input.scss +3 -0
  57. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/radios/_index.scss +354 -0
  58. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/radios/_radios.scss +3 -0
  59. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/select/_index.scss +63 -0
  60. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/select/_select.scss +3 -0
  61. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/skip-link/_index.scss +48 -0
  62. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/skip-link/_skip-link.scss +3 -0
  63. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/summary-list/_index.scss +215 -0
  64. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/summary-list/_summary-list.scss +3 -0
  65. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/tables/_index.scss +205 -0
  66. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/tables/_tables.scss +3 -0
  67. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/tabs/_index.scss +138 -0
  68. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/tabs/_tabs.scss +3 -0
  69. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/tag/_index.scss +101 -0
  70. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/tag/_tag.scss +3 -0
  71. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/task-list/_index.scss +111 -0
  72. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/task-list/_task-list.scss +3 -0
  73. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/textarea/_index.scss +52 -0
  74. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/textarea/_textarea.scss +3 -0
  75. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/warning-callout/_index.scss +22 -0
  76. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/components/warning-callout/_warning-callout.scss +3 -0
  77. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/_index.scss +4 -0
  78. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/_nhsuk-frontend-properties.scss +28 -0
  79. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/all.scss +3 -1
  80. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/elements/_forms.scss +4 -2
  81. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/elements/_index.scss +2 -0
  82. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/elements/_links.scss +3 -2
  83. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/elements/_page.scss +66 -0
  84. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/elements/_table.scss +6 -5
  85. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/generic/_box-sizing.scss +2 -4
  86. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/generic/_font-face.scss +29 -15
  87. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/generic/_index.scss +2 -0
  88. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/helpers/_colour.scss +106 -0
  89. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/helpers/_index.scss +7 -0
  90. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/objects/_button-group.scss +124 -0
  91. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/objects/_form-group.scss +47 -0
  92. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/objects/_grid.scss +5 -3
  93. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/objects/_index.scss +4 -0
  94. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/objects/_input-wrapper.scss +81 -0
  95. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/objects/_main-wrapper.scss +66 -0
  96. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/objects/_width-container.scss +98 -0
  97. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/settings/_all.scss +3 -1
  98. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/settings/_breakpoints.scss +35 -0
  99. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/settings/_colours-applied.scss +326 -0
  100. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/settings/_colours-deprecated.scss +116 -0
  101. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/settings/_colours-palette.scss +41 -0
  102. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/settings/_colours.scss +12 -0
  103. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/settings/_globals.scss +214 -0
  104. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/settings/_index.scss +5 -1
  105. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/settings/_spacing.scss +3 -3
  106. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/settings/_typography.scss +15 -34
  107. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/settings/_warnings.scss +11 -5
  108. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/styles/_icons.scss +45 -0
  109. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/styles/_index.scss +2 -0
  110. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/styles/_lists.scss +15 -10
  111. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/styles/_section-break.scss +4 -2
  112. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/styles/_typography.scss +34 -39
  113. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_all.scss +3 -1
  114. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/tools/_buttons.scss +85 -0
  115. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_exports.scss +1 -11
  116. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/tools/_focused.scss +134 -0
  117. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/tools/_functions.scss +81 -0
  118. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/tools/_grid.scss +74 -0
  119. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_index.scss +5 -1
  120. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/tools/_links.scss +234 -0
  121. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_mixins.scss +168 -118
  122. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_sass-mq.scss +9 -11
  123. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_shape-arrow.scss +14 -20
  124. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/tools/_shape-chevron.scss +65 -0
  125. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/tools/_shape-dash.scss +31 -0
  126. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_spacing.scss +25 -14
  127. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/tools/_typography.scss +71 -25
  128. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_clearfix.scss +2 -0
  129. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_display.scss +2 -0
  130. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_float.scss +2 -0
  131. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_grid-widths.scss +19 -20
  132. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_index.scss +2 -0
  133. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_link-nowrap.scss +2 -0
  134. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_list-border.scss +6 -2
  135. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_reading-width.scss +2 -0
  136. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_spacing.scss +6 -0
  137. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_text-align.scss +2 -0
  138. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/core/utilities/_typography.scss +52 -0
  139. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_visually-hidden.scss +2 -0
  140. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/utilities/_widths.scss +2 -0
  141. data/app/assets/stylesheets/design_system/{nhsuk-frontend-9.6.4 → nhsuk-frontend-10.3.1}/core/vendor/sass-mq.scss +4 -2
  142. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/index.scss +4 -0
  143. data/app/assets/stylesheets/design_system/nhsuk-frontend-10.3.1/nhsuk.scss +3 -0
  144. data/app/assets/stylesheets/design_system/nhsuk.scss +2 -2
  145. data/app/helpers/design_system_helper.rb +8 -4
  146. data/app/views/layouts/govuk/application.html.erb +1 -0
  147. data/app/views/layouts/nhsuk/application.html.erb +52 -59
  148. data/app/views/nhsuk/_navigation.html.erb +9 -13
  149. data/lib/design_system/engine.rb +1 -1
  150. data/lib/design_system/generic/builders/action_link.rb +17 -0
  151. data/lib/design_system/generic/builders/elements/backlink.rb +30 -0
  152. data/lib/design_system/generic/builders/fixed_elements.rb +4 -0
  153. data/lib/design_system/generic/builders/link.rb +9 -0
  154. data/lib/design_system/generic/builders/notification.rb +10 -6
  155. data/lib/design_system/generic/builders/pagination_renderer.rb +4 -9
  156. data/lib/design_system/govuk/builders/action_link.rb +17 -0
  157. data/lib/design_system/govuk/form_builder.rb +6 -2
  158. data/lib/design_system/govuk/test_helpers/form_builder_testable.rb +14 -0
  159. data/lib/design_system/nhsuk/builders/action_link.rb +30 -0
  160. data/lib/design_system/nhsuk/builders/elements/breadcrumbs.rb +12 -16
  161. data/lib/design_system/nhsuk/builders/notification.rb +0 -6
  162. data/lib/design_system/version.rb +1 -1
  163. data/lib/tasks/nhsuk.rake +10 -5
  164. data/public/design_system/static/{nhsuk-frontend-9.6.4/favicons → nhsuk-frontend-10.3.1/images}/favicon.ico +0 -0
  165. data/public/design_system/static/nhsuk-frontend-10.3.1/images/favicon.svg +4 -0
  166. data/public/design_system/static/nhsuk-frontend-10.3.1/images/nhsuk-icon-180.png +0 -0
  167. data/public/design_system/static/nhsuk-frontend-10.3.1/images/nhsuk-icon-192.png +0 -0
  168. data/public/design_system/static/nhsuk-frontend-10.3.1/images/nhsuk-icon-512.png +0 -0
  169. data/public/design_system/static/nhsuk-frontend-10.3.1/images/nhsuk-icon-mask.svg +3 -0
  170. data/public/design_system/static/nhsuk-frontend-10.3.1/images/nhsuk-opengraph-image.png +0 -0
  171. data/public/design_system/static/nhsuk-frontend-10.3.1/manifest.json +39 -0
  172. data/public/design_system/static/nhsuk-frontend-10.3.1/nhsuk-frontend.min.js +1 -0
  173. data/public/design_system/static/nhsuk-frontend-10.3.1/nhsuk-frontend.min.js.map +1 -0
  174. data/public/design_system/static/nhsuk-frontend-10.3.1/nhsuk.js +7 -0
  175. metadata +159 -161
  176. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/action-link/_action-link.scss +0 -1
  177. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/action-link/_index.scss +0 -73
  178. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/back-link/_back-link.scss +0 -1
  179. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/back-link/_index.scss +0 -66
  180. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/breadcrumb/_breadcrumb.scss +0 -1
  181. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/breadcrumb/_index.scss +0 -138
  182. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/button/_button.scss +0 -1
  183. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/button/_index.scss +0 -257
  184. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/card/_card.scss +0 -1
  185. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/card/_index.scss +0 -321
  186. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/character-count/_character-count.scss +0 -1
  187. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/character-count/_index.scss +0 -19
  188. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/checkboxes/_checkboxes.scss +0 -1
  189. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/checkboxes/_index.scss +0 -155
  190. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/contents-list/_contents-list.scss +0 -1
  191. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/contents-list/_index.scss +0 -40
  192. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/date-input/_date-input.scss +0 -1
  193. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/date-input/_index.scss +0 -29
  194. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/details/_details.scss +0 -1
  195. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/details/_index.scss +0 -211
  196. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/do-dont-list/_do-dont-list.scss +0 -1
  197. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/do-dont-list/_index.scss +0 -23
  198. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/error-message/_error-message.scss +0 -1
  199. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/error-message/_index.scss +0 -17
  200. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/error-summary/_error-summary.scss +0 -1
  201. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/error-summary/_index.scss +0 -72
  202. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/fieldset/_fieldset.scss +0 -1
  203. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/fieldset/_index.scss +0 -65
  204. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/footer/_footer.scss +0 -1
  205. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/footer/_index.scss +0 -87
  206. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/header/_header-base.scss +0 -495
  207. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/header/_header-organisation.scss +0 -126
  208. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/header/_header-service.scss +0 -60
  209. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/header/_header-transactional.scss +0 -61
  210. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/header/_header-white.scss +0 -117
  211. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/header/_header.scss +0 -1
  212. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/header/_index.scss +0 -5
  213. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/hero/_hero.scss +0 -1
  214. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/hero/_index.scss +0 -187
  215. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/hint/_hint.scss +0 -1
  216. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/hint/_index.scss +0 -51
  217. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/images/_images.scss +0 -1
  218. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/images/_index.scss +0 -48
  219. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/input/_index.scss +0 -149
  220. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/input/_input.scss +0 -1
  221. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/inset-text/_index.scss +0 -28
  222. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/inset-text/_inset-text.scss +0 -1
  223. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/label/_index.scss +0 -53
  224. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/label/_label.scss +0 -1
  225. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/pagination/_index.scss +0 -95
  226. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/pagination/_pagination.scss +0 -1
  227. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/panel/_index.scss +0 -57
  228. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/panel/_panel.scss +0 -1
  229. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/radios/_index.scss +0 -180
  230. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/radios/_radios.scss +0 -1
  231. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/select/_index.scss +0 -44
  232. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/select/_select.scss +0 -1
  233. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/skip-link/_index.scss +0 -34
  234. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/skip-link/_skip-link.scss +0 -1
  235. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/summary-list/_index.scss +0 -183
  236. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/summary-list/_summary-list.scss +0 -1
  237. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/tables/_index.scss +0 -181
  238. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/tables/_tables.scss +0 -1
  239. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/tabs/_index.scss +0 -120
  240. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/tabs/_tabs.scss +0 -1
  241. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/tag/_index.scss +0 -92
  242. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/tag/_tag.scss +0 -1
  243. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/task-list/_index.scss +0 -101
  244. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/task-list/_task-list.scss +0 -1
  245. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/textarea/_index.scss +0 -30
  246. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/textarea/_textarea.scss +0 -1
  247. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/warning-callout/_index.scss +0 -19
  248. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/components/warning-callout/_warning-callout.scss +0 -1
  249. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/elements/_page.scss +0 -43
  250. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/objects/_form-group.scss +0 -25
  251. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/objects/_main-wrapper.scss +0 -96
  252. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/objects/_width-container.scss +0 -63
  253. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/settings/_breakpoints.scss +0 -18
  254. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/settings/_colours.scss +0 -188
  255. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/settings/_globals.scss +0 -82
  256. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/styles/_icons.scss +0 -105
  257. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/tools/_focused.scss +0 -86
  258. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/tools/_functions.scss +0 -45
  259. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/tools/_grid.scss +0 -138
  260. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/tools/_ifff.scss +0 -19
  261. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/tools/_links.scss +0 -184
  262. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/core/utilities/_typography.scss +0 -72
  263. data/app/assets/stylesheets/design_system/nhsuk-frontend-9.6.4/nhsuk.scss +0 -1
  264. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/apple-touch-icon-180x180.png +0 -0
  265. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/apple-touch-icon.png +0 -0
  266. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/favicon-192x192.png +0 -0
  267. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/favicon.png +0 -0
  268. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/favicon.svg +0 -3
  269. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/largetile-310x310.png +0 -0
  270. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/mediumtile-144x144.png +0 -0
  271. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/mediumtile-150x150.png +0 -0
  272. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/smalltile-70x70.png +0 -0
  273. data/public/design_system/static/nhsuk-frontend-9.6.4/favicons/widetile-310x150.png +0 -0
  274. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-arrow-left.svg +0 -3
  275. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-arrow-right-circle.svg +0 -4
  276. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-arrow-right.svg +0 -3
  277. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-chevron-left.svg +0 -3
  278. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-chevron-right.svg +0 -3
  279. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-close.svg +0 -3
  280. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-cross.svg +0 -4
  281. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-emdash-small.svg +0 -3
  282. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-emdash.svg +0 -3
  283. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-minus.svg +0 -4
  284. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-plus.svg +0 -4
  285. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-search.svg +0 -3
  286. data/public/design_system/static/nhsuk-frontend-9.6.4/icons/icon-tick.svg +0 -3
  287. data/public/design_system/static/nhsuk-frontend-9.6.4/logos/logo-nhs.svg +0 -5
  288. data/public/design_system/static/nhsuk-frontend-9.6.4/logos/nhs-logo.png +0 -0
  289. data/public/design_system/static/nhsuk-frontend-9.6.4/logos/open-graph.png +0 -0
  290. data/public/design_system/static/nhsuk-frontend-9.6.4/nhsuk.js +0 -4
  291. data/public/design_system/static/nhsuk-frontend-9.6.4/nhsuk.min.js +0 -1
  292. /data/public/design_system/static/{design_system-0.10.0 → design_system-0.12.0}/design_system.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nhsuk-frontend.min.js","sources":["../../src/nhsuk/common/closest-attribute-value.mjs","../../src/nhsuk/common/nhsuk-frontend-version.mjs","../../src/nhsuk/common/index.mjs","../../src/nhsuk/common/configuration/normalise-string.mjs","../../src/nhsuk/common/configuration/extract-config-by-namespace.mjs","../../src/nhsuk/common/configuration/merge-configs.mjs","../../src/nhsuk/errors/index.mjs","../../src/nhsuk/common/configuration/normalise-options.mjs","../../src/nhsuk/component.mjs","../../src/nhsuk/configurable-component.mjs","../../src/nhsuk/common/configuration/normalise-dataset.mjs","../../src/nhsuk/components/button/button.mjs","../../src/nhsuk/i18n.mjs","../../src/nhsuk/components/character-count/character-count.mjs","../../src/nhsuk/common/configuration/validate-config.mjs","../../src/nhsuk/components/checkboxes/checkboxes.mjs","../../src/nhsuk/components/error-summary/error-summary.mjs","../../src/nhsuk/components/file-upload/file-upload.mjs","../../src/nhsuk/components/header/header.mjs","../../src/nhsuk/components/notification-banner/notification-banner.mjs","../../src/nhsuk/components/password-input/password-input.mjs","../../src/nhsuk/components/radios/radios.mjs","../../src/nhsuk/components/skip-link/skip-link.mjs","../../src/nhsuk/components/tabs/tabs.mjs","../../src/nhsuk/index.mjs"],"sourcesContent":["/**\n * Returns the value of the given attribute closest to the given element (including itself)\n *\n * @param {Element} $element - The element to start walking the DOM tree up\n * @param {string} attributeName - The name of the attribute\n * @returns {string | null} Attribute value\n */\nexport function closestAttributeValue($element, attributeName) {\n const $closestElementWithAttribute = $element.closest(`[${attributeName}]`)\n return $closestElementWithAttribute\n ? $closestElementWithAttribute.getAttribute(attributeName)\n : null\n}\n","/*\n * This variable is automatically overwritten during builds and releases.\n * It doesn't need to be updated manually.\n */\n\n/**\n * NHS.UK frontend release version\n *\n * {@link https://github.com/nhsuk/nhsuk-frontend/releases}\n */\nexport const version = 'development'\n","/**\n * Toggle a toggle a class on conditional content for an input based on checked state\n *\n * @param {Element | null} $input - input element\n * @param {string} className - class to toggle\n */\nexport function toggleConditionalInput($input, className) {\n if (!$input || !($input instanceof HTMLInputElement) || !className) {\n return\n }\n\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const target = document.getElementById(targetId)\n if (!target) {\n return\n }\n\n $input.setAttribute('aria-expanded', $input.checked.toString())\n target.classList.toggle(className, !$input.checked)\n}\n\n/**\n * Get NHS.UK frontend breakpoint value from CSS custom property\n *\n * @param {string} name - Breakpoint name\n */\nexport function getBreakpoint(name) {\n const property = `--nhsuk-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * Original code taken from GDS (Government Digital Service)\n * {@link https://github.com/alphagov/govuk-frontend}\n *\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.removeEventListener('focus', onFocus)\n $element.addEventListener('blur', onBlur)\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n $element.removeEventListener('blur', onBlur)\n\n if (options.onBlur) {\n options.onBlur.call($element)\n }\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus)\n\n // Focus element\n if (options.onBeforeFocus) {\n options.onBeforeFocus.call($element)\n }\n\n $element.focus()\n}\n\n/**\n * Checks if component is already initialised\n *\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\n}\n\n/**\n * Checks if NHS.UK frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but NHS.UK frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether NHS.UK frontend is supported on this page\n */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('nhsuk-frontend-supported')\n}\n\n/**\n * Check for an object\n *\n * @template {Partial<Record<keyof ObjectType, unknown>>} ObjectType\n * @param {unknown | ObjectType} option - Option to check\n * @returns {option is ObjectType} Whether the option is an object\n */\nexport function isObject(option) {\n return !!option && typeof option === 'object' && !Array.isArray(option)\n}\n\n/**\n * Check for valid scope\n *\n * @template {Element | Document} ScopeType\n * @param {unknown | ScopeType} $scope - Scope of the document to search within\n * @returns {$scope is ScopeType} Whether the scope can be queried\n */\nexport function isScope($scope) {\n return !!$scope && ($scope instanceof Element || $scope instanceof Document)\n}\n\n/**\n * Format error message\n *\n * @param {CompatibleClass} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\nexport * from './closest-attribute-value.mjs'\nexport * from './nhsuk-frontend-version.mjs'\n\n/**\n * @import { CompatibleClass } from '../component.mjs'\n */\n","/**\n * Normalise string\n *\n * 'If it looks like a duck, and it quacks like a duck…' 🦆\n *\n * If the passed value looks like a boolean or a number, convert it to a boolean\n * or number.\n *\n * Designed to be used to convert config passed via data attributes (which are\n * always strings) into something sensible.\n *\n * @param {string | number | boolean | undefined} value - The value to normalise\n * @param {SchemaProperty} [property] - Component schema property\n * @returns Normalised data\n */\nexport function normaliseString(value, property) {\n if (!isValid(value)) {\n return\n }\n\n const trimmedValue = value.toString().trim()\n\n let output\n let outputType = property?.type\n\n // No schema type set? Determine automatically\n if (!outputType) {\n if (['true', 'false'].includes(trimmedValue)) {\n outputType = 'boolean'\n }\n\n // Empty / whitespace-only strings are considered finite so we need to check\n // the length of the trimmed string as well\n if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {\n outputType = 'number'\n }\n }\n\n switch (outputType) {\n case 'boolean':\n output = trimmedValue === 'true'\n break\n\n case 'number':\n output = Number(trimmedValue)\n break\n\n default:\n output = value\n }\n\n return output\n}\n\n/**\n * Normalise array of strings\n *\n * @param {string | (string | number | boolean | undefined)[] | undefined} value - The value to normalise\n * @returns Normalised array of data\n */\nexport function normaliseArray(value) {\n let values = Array.isArray(value) ? value : []\n\n // Attempt to parse string as array\n if (typeof value === 'string') {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n values = JSON.parse(decodeURIComponent(value), getArrayValue) ?? []\n } catch {\n return []\n }\n }\n\n // Normalise and filter array values\n return values\n .map((value) => normaliseString(value))\n .filter((value) => value !== undefined)\n}\n\n/**\n * Accept valid array values only\n *\n * Used as reviver function in `JSON.parse()`\n *\n * @this {unknown}\n * @param {string} key\n * @param {unknown} value\n */\nfunction getArrayValue(key, value) {\n return isValid(value) || (key === '' && Array.isArray(value))\n ? value\n : undefined\n}\n\n/**\n * Whether value is valid\n *\n * @param {unknown} value\n */\nfunction isValid(value) {\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * @import { SchemaProperty } from './index.mjs'\n */\n","import { isObject } from '../index.mjs'\n\nimport { normaliseString } from './normalise-string.mjs'\n\n/**\n * Extracts keys starting with a particular namespace from dataset ('data-*')\n * object, removing the namespace in the process, normalising all values\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @param {Schema<ConfigurationType>} schema - The schema of a component\n * @param {DOMStringMap} dataset - The object to extract key-value pairs from\n * @param {keyof ConfigurationType} namespace - The namespace to filter keys with\n * @returns {ObjectNested | undefined} Nested object with dot-separated key namespace removed\n */\nexport function extractConfigByNamespace(schema, dataset, namespace) {\n const property = schema.properties[namespace]\n\n // Only extract configs for object schema properties\n if (property?.type !== 'object') {\n return\n }\n\n // Add default empty config\n const newObject = /** @type {Record<typeof namespace, ObjectNested>} */ ({\n [namespace]: {}\n })\n\n for (const [key, value] of Object.entries(dataset)) {\n /** @type {ObjectNested | ObjectNested[NestedKey]} */\n let current = newObject\n\n // Split the key into parts, using . as our namespace separator\n const keyParts = key.split('.')\n\n /**\n * Create new level per part\n *\n * e.g. 'i18n.textareaDescription.other' becomes\n * `{ i18n: { textareaDescription: { other } } }`\n */\n for (const [index, name] of keyParts.entries()) {\n if (isObject(current)) {\n // Drop down to nested object until the last part\n if (index < keyParts.length - 1) {\n // New nested object (optionally) replaces existing value\n if (!isObject(current[name])) {\n current[name] = {}\n }\n\n // Drop down into new or existing nested object\n current = current[name]\n } else if (key !== namespace) {\n // Normalised value (optionally) replaces existing value\n current[name] = normaliseString(value)\n }\n }\n }\n }\n\n return newObject[namespace]\n}\n\n/**\n * Schema for component config\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @typedef {object} Schema\n * @property {Record<keyof ConfigurationType, SchemaProperty | undefined>} properties - Schema properties\n * @property {SchemaCondition<ConfigurationType>[]} [anyOf] - List of schema conditions\n */\n\n/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object' | 'array'} type - Property type\n */\n\n/**\n * Schema condition for component config\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @typedef {object} SchemaCondition\n * @property {(keyof ConfigurationType)[]} required - List of required config fields\n * @property {string} errorMessage - Error message when required config fields not provided\n */\n\n/**\n * @typedef {keyof ObjectNested} NestedKey\n * @typedef {{ [key: string]: string | boolean | number | (string | number | boolean)[] | ObjectNested | undefined }} ObjectNested\n */\n","import { isObject } from '../index.mjs'\n\n/**\n * Config merging function\n *\n * Takes any number of objects and combines them together, with\n * greatest priority on the LAST item passed in.\n *\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns A merged config object\n */\nexport function mergeConfigs(...configObjects) {\n // Start with an empty object as our base\n /** @type {{ [key: string]: unknown }} */\n const formattedConfigObject = {}\n\n // Loop through each of the passed objects\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key]\n const override = configObject[key]\n\n // Push their keys one-by-one into formattedConfigObject. Any duplicate\n // keys with object values will be merged, otherwise the new value will\n // override the existing value.\n if (isObject(option) && isObject(override)) {\n formattedConfigObject[key] = mergeConfigs(option, override)\n } else {\n // Apply override\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n}\n","import { formatErrorMessage } from '../common/index.mjs'\n\n/**\n * NHS.UK frontend error\n *\n * A base class for `Error`s thrown by NHS.UK frontend.\n *\n * It is meant to be extended into specific types of errors\n * to be thrown by our code.\n *\n * @example\n * ```js\n * class MissingRootError extends NHSUKFrontendError {\n * // Setting an explicit name is important as extending the class will not\n * // set a new `name` on the subclass. The `name` property is important\n * // to ensure intelligible error names even if the class name gets\n * // mangled by a minifier\n * name = \"MissingRootError\"\n * }\n * ```\n * @abstract\n */\nexport class NHSUKFrontendError extends Error {\n name = 'NHSUKFrontendError'\n}\n\n/**\n * Indicates that NHS.UK frontend is not supported\n */\nexport class SupportError extends NHSUKFrontendError {\n name = 'SupportError'\n\n /**\n * Checks if NHS.UK frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage =\n 'noModule' in HTMLScriptElement.prototype\n ? 'NHS.UK frontend initialised without `<body class=\"nhsuk-frontend-supported\">` from template `<script>` snippet'\n : 'NHS.UK frontend is not supported in this browser'\n\n super(\n $scope\n ? supportMessage\n : 'NHS.UK frontend initialised without `<script type=\"module\">`'\n )\n }\n}\n\n/**\n * Indicates that a component has received an illegal configuration\n */\nexport class ConfigError extends NHSUKFrontendError {\n name = 'ConfigError'\n}\n\n/**\n * Indicates an issue with an element (possibly `null` or `undefined`)\n */\nexport class ElementError extends NHSUKFrontendError {\n name = 'ElementError'\n\n /**\n * @param {ElementErrorOptions} options - Element error options\n */\n constructor(options) {\n const { component, identifier, element, expectedType } = options\n\n let message = identifier\n\n // Append reason\n message += element\n ? ` is not of type ${expectedType ?? 'HTMLElement'}`\n : ' not found'\n\n // Prepend with module name (optional)\n if (component) {\n message = formatErrorMessage(component, message)\n }\n\n super(message)\n }\n}\n\n/**\n * Indicates that a component is already initialised\n */\nexport class InitError extends NHSUKFrontendError {\n name = 'InitError'\n\n /**\n * @param {CompatibleClass | string} componentOrMessage - Component or init error message\n */\n constructor(componentOrMessage) {\n const message =\n typeof componentOrMessage === 'string'\n ? componentOrMessage\n : formatErrorMessage(\n componentOrMessage,\n 'Root element (`$root`) already initialised'\n )\n\n super(message)\n }\n}\n\n/**\n * Element error options\n *\n * @typedef {object} ElementErrorOptions\n * @property {Element | Document | null} [element] - The element in error (optional)\n * @property {CompatibleClass} [component] - Component throwing the error (optional)\n * @property {string} identifier - An identifier that'll let the user understand which element has an error. This is whatever makes the most sense\n * @property {string} [expectedType] - The type that was expected for the identifier\n */\n\n/**\n * @import { CompatibleClass } from '../component.mjs'\n */\n","import { isObject, isScope } from '../index.mjs'\n\n/**\n * Normalise options passed to `initAll` or `createAll`\n *\n * @template {CompatibleClass} ComponentClass\n * @param {Config | CreateAllOptions<ComponentClass> | OnErrorCallback<ComponentClass> | Element | Document | null} [scopeOrOptions] - Scope of the document to search within, initialisation options or error callback function\n * @returns {CreateAllOptions<ComponentClass>} Normalised options\n */\nexport function normaliseOptions(scopeOrOptions) {\n let /** @type {Element | Document | null} */ $scope = document\n let /** @type {OnErrorCallback<ComponentClass> | undefined} */ onError\n\n // Handle options object\n if (isObject(scopeOrOptions)) {\n const options = scopeOrOptions\n\n // Scope must be valid or null\n if (isScope(options.scope) || options.scope === null) {\n $scope = options.scope\n }\n\n // Error handler must be a function\n if (typeof options.onError === 'function') {\n onError = options.onError\n }\n }\n\n if (isScope(scopeOrOptions)) {\n $scope = scopeOrOptions\n } else if (scopeOrOptions === null) {\n $scope = null\n } else if (typeof scopeOrOptions === 'function') {\n onError = scopeOrOptions\n }\n\n return {\n scope: $scope,\n onError\n }\n}\n\n/**\n * @import { CompatibleClass } from '../../component.mjs'\n * @import { Config, CreateAllOptions, OnErrorCallback } from '../../index.mjs'\n */\n","import { isInitialised, isSupported } from './common/index.mjs'\nimport { ElementError, InitError, SupportError } from './errors/index.mjs'\n\nconst _self =\n typeof globalThis !== 'undefined'\n ? globalThis // Modern browsers, Node.js\n : self // Old browsers, web workers\n\n/**\n * Base component class\n *\n * Centralises the behaviours shared by our components\n *\n * @abstract\n * @template {Element} [RootElementType=HTMLElement]\n */\nexport class Component {\n /**\n * @type {typeof Element}\n */\n static elementType = _self.HTMLElement\n\n /**\n * @type {RootElementType}\n */\n $root\n\n /**\n * Constructs a new component, validating that NHS.UK frontend is supported\n *\n * @param {Element | null} $root - HTML element to use for component\n */\n constructor($root) {\n const childConstructor = /** @type {ComponentConstructor} */ (\n this.constructor\n )\n\n if (!$root || !($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n })\n }\n\n this.$root = /** @type {RootElementType} */ ($root)\n\n childConstructor.checkSupport()\n\n this.checkInitialised()\n\n const { moduleName } = childConstructor\n this.$root.setAttribute(`data-${moduleName}-init`, '')\n }\n\n /**\n * Validates whether component is already initialised\n *\n * @throws {InitError} when component is already initialised\n */\n checkInitialised() {\n const childConstructor = /** @type {ComponentConstructor} */ (\n this.constructor\n )\n\n if (isInitialised(this.$root, childConstructor.moduleName)) {\n throw new InitError(childConstructor)\n }\n }\n\n /**\n * Validates whether components are supported\n *\n * @throws {SupportError} when the components are not supported\n */\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError()\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-component'\n}\n\n/**\n * Component compatible class\n *\n * @template {typeof Component | typeof ConfigurableComponent} [ComponentType=typeof Component]\n * @typedef {{\n * new(...args: ConstructorParameters<ComponentType>): InstanceType<ComponentType>,\n * defaults?: ObjectNested,\n * schema?: Schema<ObjectNested>,\n * moduleName: string\n * }} CompatibleClass\n */\n\n/**\n * Component constructor\n *\n * @template {typeof Component | typeof ConfigurableComponent} [ComponentType=typeof Component]\n * @typedef {CompatibleClass & ComponentType} ComponentConstructor\n */\n\n/**\n * Component initialisation options\n *\n * @typedef {object} InitOptions\n * @property {Element | Document | null} [scope] - Scope of the document to search within\n */\n\n/**\n * @import { ObjectNested, Schema } from './common/configuration/index.mjs'\n * @import { ConfigurableComponent } from './configurable-component.mjs'\n */\n","import {\n mergeConfigs,\n normaliseDataset\n} from './common/configuration/index.mjs'\nimport { formatErrorMessage, isObject } from './common/index.mjs'\nimport { Component } from './component.mjs'\nimport { ConfigError } from './errors/index.mjs'\n\n/**\n * Configurable base component class\n *\n * @abstract\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @template {HTMLElement} [RootElementType=HTMLElement]\n * @augments {Component<RootElementType>}\n */\nexport class ConfigurableComponent extends Component {\n /**\n * @type {ConfigurationType}\n */\n config\n\n /**\n * Constructs a new component, validating that NHS.UK frontend is supported\n *\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<ConfigurationType>} [config] - HTML element to use for component\n */\n constructor($root, config) {\n super($root)\n\n const childConstructor =\n /** @type {ComponentConstructor<typeof ConfigurableComponent>} */ (\n this.constructor\n )\n\n if (!isObject(childConstructor.defaults)) {\n throw new ConfigError(\n formatErrorMessage(\n childConstructor,\n 'Config passed as parameter into constructor but no defaults defined'\n )\n )\n }\n\n const datasetConfig = /** @type {Partial<ConfigurationType>} */ (\n normaliseDataset(childConstructor, this.$root.dataset)\n )\n\n // Override defaults with JavaScript config\n this.config = /** @type {ConfigurationType} */ (\n mergeConfigs(childConstructor.defaults, config ?? {})\n )\n\n // Override merged config with dataset config\n this.config = /** @type {ConfigurationType} */ (\n mergeConfigs(\n this.config,\n this.configOverride(datasetConfig),\n datasetConfig\n )\n )\n }\n\n /**\n * Config override\n *\n * It should take a subset of configuration as input and return\n * a new configuration object with properties that should be\n * overridden based on the root element's dataset\n *\n * @abstract\n * @param {Partial<ConfigurationType>} _datasetConfig - Config specified by dataset\n * @returns {Partial<ConfigurationType>} Config to override by dataset\n */\n configOverride(_datasetConfig = {}) {\n return {}\n }\n}\n\n/**\n * @import { ObjectNested } from './common/configuration/index.mjs'\n * @import { ComponentConstructor } from './component.mjs'\n */\n","import { ConfigError } from '../../errors/index.mjs'\nimport { formatErrorMessage, isObject } from '../index.mjs'\n\nimport { extractConfigByNamespace } from './extract-config-by-namespace.mjs'\nimport { normaliseArray, normaliseString } from './normalise-string.mjs'\n\n/**\n * Normalise dataset\n *\n * Loop over an object and normalise each value using {@link normaliseString},\n * optionally expanding `data-i18n.property` nested values\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @template {[keyof ConfigurationType, SchemaProperty | undefined][]} SchemaEntryType\n * @param {CompatibleClass & { schema?: Schema<ConfigurationType> }} Component - Component class\n * @param {DOMStringMap} dataset - HTML element dataset\n * @returns {ObjectNested} Normalised dataset\n */\nexport function normaliseDataset(Component, dataset) {\n if (!isObject(Component.schema)) {\n throw new ConfigError(\n formatErrorMessage(\n Component,\n 'Config passed as parameter into constructor but no schema defined'\n )\n )\n }\n\n const out = /** @type {ObjectNested} */ ({})\n const entries = /** @type {SchemaEntryType} */ (\n Object.entries(Component.schema.properties)\n )\n\n // Normalise top-level dataset ('data-*') values using schema types\n for (const entry of entries) {\n const [namespace, property] = entry\n\n // Cast the `namespace` to string so it can be used to access the dataset\n const field = namespace.toString()\n\n if (field in dataset) {\n out[field] =\n property?.type === 'array'\n ? normaliseArray(dataset[field])\n : normaliseString(dataset[field], property)\n }\n\n /**\n * Extract and normalise nested object values automatically using\n * {@link normaliseString} but only schema object types are allowed\n */\n if (property?.type === 'object') {\n out[field] = extractConfigByNamespace(\n Component.schema,\n dataset,\n namespace\n )\n }\n }\n\n return out\n}\n\n/**\n * @import { CompatibleClass } from '../../component.mjs'\n * @import { ObjectNested, Schema, SchemaProperty } from './index.mjs'\n */\n","import { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\n\nconst DEBOUNCE_TIMEOUT_IN_SECONDS = 1\n\n/**\n * Button component\n *\n * @augments {ConfigurableComponent<ButtonConfig>}\n */\nexport class Button extends ConfigurableComponent {\n /**\n * @type {number | null}\n */\n debounceFormSubmitTimer = null\n\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<ButtonConfig>} [config] - Button config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n /**\n * Initialise an event listener for keydown at document level\n * this will help listening for later inserted elements with a role=\"button\"\n */\n this.$root.addEventListener('keydown', (event) => this.handleKeyDown(event))\n this.$root.addEventListener('click', (event) => this.debounce(event))\n }\n\n /**\n * JavaScript 'shim' to trigger the click event of element(s) when the space key is pressed.\n *\n * Created since some Assistive Technologies (for example some Screenreaders)\n * will tell a user to press space on a 'button', so this functionality needs to be shimmed\n * See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270\n *\n * @param {KeyboardEvent} event - Keydown event\n */\n handleKeyDown(event) {\n const target = event.target\n\n // Handle space bar only\n if (event.key !== ' ') {\n return\n }\n\n // Handle elements with [role=\"button\"] only\n if (\n target instanceof HTMLElement &&\n target.getAttribute('role') === 'button'\n ) {\n event.preventDefault()\n target.click()\n }\n }\n\n /**\n * Debounce double-clicks\n *\n * If the click quickly succeeds a previous click then nothing will happen.\n * This stops people accidentally causing multiple form submissions by\n * double clicking buttons.\n *\n * @param {MouseEvent} event - Mouse click event\n * @returns {undefined | false} Returns undefined, or false when debounced\n */\n debounce(event) {\n // Check the button that was clicked has preventDoubleClick enabled\n if (!this.config.preventDoubleClick) {\n return\n }\n\n // If the timer is still running then we want to prevent the click from submitting the form\n if (this.debounceFormSubmitTimer) {\n event.preventDefault()\n return false\n }\n\n this.debounceFormSubmitTimer = window.setTimeout(() => {\n this.debounceFormSubmitTimer = null\n }, DEBOUNCE_TIMEOUT_IN_SECONDS * 1000)\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-button'\n\n /**\n * Button default config\n *\n * @see {@link ButtonConfig}\n * @constant\n * @type {ButtonConfig}\n */\n static defaults = Object.freeze({\n preventDoubleClick: false\n })\n\n /**\n * Button config schema\n *\n * @constant\n * @satisfies {Schema<ButtonConfig>}\n */\n static schema = Object.freeze({\n properties: {\n preventDoubleClick: { type: 'boolean' }\n }\n })\n}\n\n/**\n * Initialise button component\n *\n * @deprecated Use {@link createAll | `createAll(Button, options)`} instead.\n * @param {InitOptions & Partial<ButtonConfig>} [options]\n */\nexport function initButtons(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $buttons = $scope?.querySelectorAll(\n `[data-module=\"${Button.moduleName}\"]`\n )\n\n $buttons?.forEach(($root) => {\n new Button($root, options)\n })\n}\n\n/**\n * Button config\n *\n * @typedef {object} ButtonConfig\n * @property {boolean} [preventDoubleClick=false] - Prevent accidental double\n * clicks on submit buttons from submitting forms multiple times.\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { isObject } from './common/index.mjs'\n\n/**\n * Internationalisation\n *\n * Adds support for selecting messages to render, with placeholder\n * interpolation and locale-aware number formatting and pluralisation\n */\nexport class I18n {\n /**\n * @param {{ [key: string]: string | TranslationPluralForms }} translations - Key-value pairs of the translation strings to use.\n * @param {object} [config] - Configuration options for the function.\n * @param {string | null} [config.locale] - An overriding locale for the PluralRules functionality.\n */\n constructor(translations = {}, config = {}) {\n // Make list of translations available throughout function\n this.translations = translations\n\n // The locale to use for PluralRules and NumberFormat\n this.locale = config.locale ?? (document.documentElement.lang || 'en')\n }\n\n /**\n * The most used function - takes the key for a given piece of UI text and\n * returns the appropriate string.\n *\n * @param {string} lookupKey - The lookup key of the string to use.\n * @param {{ [key: string]: unknown }} [options] - Any options passed with the translation string, e.g: for string interpolation.\n * @returns {string} The appropriate translation string.\n * @throws {Error} Lookup key required\n * @throws {Error} Options required for `${}` placeholders\n */\n t(lookupKey, options) {\n if (!lookupKey) {\n // Print a console error if no lookup key has been provided\n throw new Error('i18n: lookup key missing')\n }\n\n // Fetch the translation for that lookup key\n let translation = this.translations[lookupKey]\n\n // If the `count` option is set, determine which plural suffix is needed and\n // change the lookupKey to match. We check to see if it's numeric instead of\n // falsy, as this could legitimately be 0.\n if (typeof options?.count === 'number' && isObject(translation)) {\n const translationPluralForm =\n translation[this.getPluralSuffix(lookupKey, options.count)]\n\n // Update translation with plural suffix\n if (translationPluralForm) {\n translation = translationPluralForm\n }\n }\n\n if (typeof translation === 'string') {\n // Check for ${} placeholders in the translation string\n // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec\n if (translation.match(/%{(.\\S+)}/)) {\n if (!options) {\n throw new Error(\n 'i18n: cannot replace placeholders in string if no option data provided'\n )\n }\n\n return this.replacePlaceholders(translation, options)\n }\n\n return translation\n }\n\n // If the key wasn't found in our translations object,\n // return the lookup key itself as the fallback\n return lookupKey\n }\n\n /**\n * Takes a translation string with placeholders, and replaces the placeholders\n * with the provided data\n *\n * @param {string} translationString - The translation string\n * @param {{ [key: string]: unknown }} options - Any options passed with the translation string, e.g: for string interpolation.\n * @returns {string} The translation string to output, with $\\{\\} placeholders replaced\n */\n replacePlaceholders(translationString, options) {\n const formatter = Intl.NumberFormat.supportedLocalesOf(this.locale).length\n ? new Intl.NumberFormat(this.locale)\n : undefined\n\n return translationString.replace(\n /%{(.\\S+)}/g,\n\n /**\n * Replace translation string placeholders\n *\n * @param {string} placeholderWithBraces - Placeholder with braces\n * @param {string} placeholderKey - Placeholder key\n * @returns {string} Placeholder value\n */\n function (placeholderWithBraces, placeholderKey) {\n if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {\n const placeholderValue = options[placeholderKey]\n\n // If a user has passed `false` as the value for the placeholder\n // treat it as though the value should not be displayed\n if (\n placeholderValue === false ||\n (typeof placeholderValue !== 'number' &&\n typeof placeholderValue !== 'string')\n ) {\n return ''\n }\n\n // If the placeholder's value is a number, localise the number formatting\n if (typeof placeholderValue === 'number') {\n return formatter\n ? formatter.format(placeholderValue)\n : `${placeholderValue}`\n }\n\n return placeholderValue\n }\n\n throw new Error(\n `i18n: no data found to replace ${placeholderWithBraces} placeholder in string`\n )\n }\n )\n }\n\n /**\n * Check to see if the browser supports Intl.PluralRules\n *\n * It requires all conditions to be met in order to be supported:\n * - The implementation of Intl supports PluralRules (NOT true in Safari 10–12)\n * - The browser/OS has plural rules for the current locale (browser dependent)\n *\n * {@link https://browsersl.ist/#q=supports+es6-module+and+not+supports+intl-pluralrules}\n *\n * @returns {boolean} Returns true if all conditions are met. Returns false otherwise.\n */\n hasIntlPluralRulesSupport() {\n return Boolean(\n 'PluralRules' in window.Intl &&\n Intl.PluralRules.supportedLocalesOf(this.locale).length\n )\n }\n\n /**\n * Get the appropriate suffix for the plural form.\n *\n * Uses Intl.PluralRules (or our own fallback implementation) to get the\n * 'preferred' form to use for the given count.\n *\n * Checks that a translation has been provided for that plural form – if it\n * hasn't, it'll fall back to the 'other' plural form (unless that doesn't exist\n * either, in which case an error will be thrown)\n *\n * @param {string} lookupKey - The lookup key of the string to use.\n * @param {number} count - Number used to determine which pluralisation to use.\n * @returns {PluralRule} The suffix associated with the correct pluralisation for this locale.\n * @throws {Error} Plural form `.other` required when preferred plural form is missing\n */\n getPluralSuffix(lookupKey, count) {\n // Validate that the number is actually a number.\n //\n // Number(count) will turn anything that can't be converted to a Number type\n // into 'NaN'. isFinite filters out NaN, as it isn't a finite number.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n count = Number(count)\n if (!isFinite(count)) {\n return 'other'\n }\n\n // Fetch the translation for that lookup key\n const translation = this.translations[lookupKey]\n\n // Check to verify that all the requirements for Intl.PluralRules are met.\n // If so, we can use that instead of our custom implementation. Otherwise,\n // use the hardcoded fallback.\n const preferredForm = this.hasIntlPluralRulesSupport()\n ? new Intl.PluralRules(this.locale).select(count)\n : 'other'\n\n // Use the correct plural form if provided\n if (isObject(translation)) {\n if (preferredForm in translation) {\n return preferredForm\n // Fall back to `other` if the plural form is missing, but log a warning\n // to the console\n } else if ('other' in translation) {\n console.warn(\n `i18n: Missing plural form \".${preferredForm}\" for \"${this.locale}\" locale. Falling back to \".other\".`\n )\n\n return 'other'\n }\n }\n\n // If the required `other` plural form is missing, all we can do is error\n throw new Error(\n `i18n: Plural form \".other\" is required for \"${this.locale}\" locale`\n )\n }\n}\n\n/**\n * Plural rule category mnemonic tags\n *\n * @typedef {'zero' | 'one' | 'two' | 'few' | 'many' | 'other'} PluralRule\n */\n\n/**\n * Translated message by plural rule they correspond to.\n *\n * Allows to group pluralised messages under a single key when passing\n * translations to a component's constructor\n *\n * @typedef {object} TranslationPluralForms\n * @property {string} [other] - General plural form\n * @property {string} [zero] - Plural form used with 0\n * @property {string} [one] - Plural form used with 1\n * @property {string} [two] - Plural form used with 2\n * @property {string} [few] - Plural form used for a few\n * @property {string} [many] - Plural form used for many\n */\n","import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'\nimport {\n normaliseOptions,\n validateConfig\n} from '../../common/configuration/index.mjs'\nimport { formatErrorMessage } from '../../common/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ConfigError, ElementError } from '../../errors/index.mjs'\nimport { I18n } from '../../i18n.mjs'\n\n/**\n * Character count component\n *\n * Tracks the number of characters or words in the `.nhsuk-js-character-count`\n * `<textarea>` inside the element. Displays a message with the remaining number\n * of characters/words available, or the number of characters/words in excess.\n *\n * You can configure the message to only appear after a certain percentage\n * of the available characters/words has been entered.\n *\n * @augments {ConfigurableComponent<CharacterCountConfig>}\n */\nexport class CharacterCount extends ConfigurableComponent {\n /**\n * @type {number | null}\n */\n lastInputTimestamp = null\n lastInputValue = ''\n\n /**\n * @type {number | null}\n */\n valueChecker = null\n\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<CharacterCountConfig>} [config] - Character count config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $textarea = this.$root.querySelector('.nhsuk-js-character-count')\n if (\n !(\n $textarea instanceof HTMLTextAreaElement ||\n $textarea instanceof HTMLInputElement\n )\n ) {\n throw new ElementError({\n component: CharacterCount,\n element: $textarea,\n expectedType: 'HTMLTextareaElement or HTMLInputElement',\n identifier: 'Form field (`.nhsuk-js-character-count`)'\n })\n }\n\n // Check for valid config\n const errors = validateConfig(CharacterCount.schema, this.config)\n if (errors[0]) {\n throw new ConfigError(formatErrorMessage(CharacterCount, errors[0]))\n }\n\n const {\n i18n,\n maxwords,\n maxlength,\n screenReaderCountMessageClass,\n textareaDescriptionClass,\n visibleCountMessageClass\n } = this.config\n\n this.i18n = new I18n(i18n, {\n // Read the fallback if necessary rather than have it set in the defaults\n locale: closestAttributeValue(this.$root, 'lang')\n })\n\n // Determine the limit attribute (characters or words)\n this.maxLength = maxwords ?? maxlength ?? Infinity\n\n this.$textarea = $textarea\n\n const textareaDescriptionId = `${this.$textarea.id}-info`\n const $textareaDescription = document.getElementById(textareaDescriptionId)\n if (!$textareaDescription) {\n throw new ElementError({\n component: CharacterCount,\n element: $textareaDescription,\n identifier: `Count message (\\`id=\"${textareaDescriptionId}\"\\`)`\n })\n }\n\n // Pre-existing validation error rendered from server\n this.$errorMessage = this.$root.querySelector('.nhsuk-error-message')\n\n // Inject a description for the textarea if none is present already\n // for when the component was rendered with no maxlength, maxwords\n // nor custom textareaDescriptionText\n if (/^\\s*$/.exec($textareaDescription.textContent)) {\n $textareaDescription.textContent = this.i18n.t('textareaDescription', {\n count: this.maxLength\n })\n }\n\n // Move the textarea description to be immediately after the textarea\n // Kept for backwards compatibility\n this.$textarea.insertAdjacentElement('afterend', $textareaDescription)\n\n // Create the *screen reader* specific live-updating counter\n // This doesn't need any styling classes, as it is never visible\n this.$screenReaderCountMessage = document.createElement('div')\n this.$screenReaderCountMessage.setAttribute('aria-live', 'polite')\n this.$screenReaderCountMessage.classList.add(\n screenReaderCountMessageClass,\n 'nhsuk-u-visually-hidden'\n )\n\n $textareaDescription.insertAdjacentElement(\n 'afterend',\n this.$screenReaderCountMessage\n )\n\n // Create our live-updating counter element, copying the classes from the\n // textarea description for backwards compatibility as these may have been\n // configured\n this.$visibleCountMessage = document.createElement('div')\n this.$visibleCountMessage.setAttribute('aria-hidden', 'true')\n this.$visibleCountMessage.className = $textareaDescription.className\n this.$visibleCountMessage.classList.add(visibleCountMessageClass)\n this.$visibleCountMessage.classList.remove(textareaDescriptionClass)\n\n $textareaDescription.insertAdjacentElement(\n 'afterend',\n this.$visibleCountMessage\n )\n\n // Hide the textarea description\n $textareaDescription.classList.add('nhsuk-u-visually-hidden')\n\n // Remove hard limit if set\n this.$textarea.removeAttribute('maxlength')\n\n this.bindChangeEvents()\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.updateCountMessage())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so update now too.\n this.updateCountMessage()\n }\n\n /**\n * Character count config override\n *\n * To ensure data-attributes take complete precedence, even if they change\n * the type of count, we need to reset the `maxlength` and `maxwords` from\n * the JavaScript config.\n *\n * @param {Partial<CharacterCountConfig>} datasetConfig - Config specified by dataset\n * @returns {Partial<CharacterCountConfig>} Config to override by dataset\n */\n configOverride(datasetConfig) {\n let configOverrides = {}\n if ('maxwords' in datasetConfig || 'maxlength' in datasetConfig) {\n configOverrides = {\n maxlength: undefined,\n maxwords: undefined\n }\n }\n\n return configOverrides\n }\n\n /**\n * Count the number of characters (or words, if `config.maxwords` is set)\n * in the given text\n *\n * @param {string} text - The text to count the characters of\n * @returns {number} the number of characters (or words) in the text\n */\n count(text) {\n if (this.config.maxwords) {\n const tokens = text.match(/\\S+/g) ?? [] // Matches consecutive non-whitespace chars\n return tokens.length\n }\n\n return text.length\n }\n\n /**\n * Bind change events\n *\n * Set up event listeners on the $textarea so that the count messages update\n * when the user types.\n */\n bindChangeEvents() {\n this.$textarea.addEventListener('keyup', () => this.handleKeyUp())\n\n // Bind focus/blur events to start/stop polling\n this.$textarea.addEventListener('focus', () => this.handleFocus())\n this.$textarea.addEventListener('blur', () => this.handleBlur())\n }\n\n /**\n * Update count message if textarea value has changed\n */\n checkIfValueChanged() {\n if (this.$textarea.value !== this.lastInputValue) {\n this.lastInputValue = this.$textarea.value\n this.updateCountMessage()\n }\n }\n\n /**\n * Update count message\n *\n * Helper function to update both the visible and screen reader-specific\n * counters simultaneously (e.g. on init)\n */\n updateCountMessage() {\n this.updateVisibleCountMessage()\n this.updateScreenReaderCountMessage()\n }\n\n /**\n * Update visible count message\n */\n updateVisibleCountMessage() {\n const remainingNumber = this.maxLength - this.count(this.$textarea.value)\n const isError = remainingNumber < 0\n\n // If input is over the threshold, remove the disabled class which renders\n // the counter invisible.\n this.$visibleCountMessage.classList.toggle(\n `${this.config.visibleCountMessageClass}--disabled`,\n !this.isOverThreshold()\n )\n\n // Update styles\n if (!this.$errorMessage) {\n // Only toggle the textarea error class if there isn't an error message\n // already, as it may be unrelated to the limit (eg: allowed characters)\n // and would set the border colour back to black.\n this.$textarea.classList.toggle('nhsuk-textarea--error', isError)\n }\n this.$visibleCountMessage.classList.toggle('nhsuk-error-message', isError)\n this.$visibleCountMessage.classList.toggle('nhsuk-hint', !isError)\n\n // Update message\n this.$visibleCountMessage.textContent = this.formattedUpdateMessage()\n }\n\n /**\n * Update screen reader count message\n */\n updateScreenReaderCountMessage() {\n // If over the threshold, remove the aria-hidden attribute, allowing screen\n // readers to announce the content of the element.\n if (this.isOverThreshold()) {\n this.$screenReaderCountMessage.removeAttribute('aria-hidden')\n } else {\n this.$screenReaderCountMessage.setAttribute('aria-hidden', 'true')\n }\n\n // Update message\n this.$screenReaderCountMessage.textContent = this.formattedUpdateMessage()\n }\n\n /**\n * Get count message\n *\n * @returns {string} Status message\n */\n formattedUpdateMessage() {\n const remainingNumber = this.maxLength - this.count(this.$textarea.value)\n const countType = this.config.maxwords ? 'words' : 'characters'\n return this.formatCountMessage(remainingNumber, countType)\n }\n\n /**\n * Formats the message shown to users according to what's counted\n * and how many remain\n *\n * @param {number} remainingNumber - The number of words/characaters remaining\n * @param {string} countType - \"words\" or \"characters\"\n * @returns {string} Status message\n */\n formatCountMessage(remainingNumber, countType) {\n if (remainingNumber === 0) {\n return this.i18n.t(`${countType}AtLimit`)\n }\n\n const translationKeySuffix =\n remainingNumber < 0 ? 'OverLimit' : 'UnderLimit'\n\n return this.i18n.t(`${countType}${translationKeySuffix}`, {\n count: Math.abs(remainingNumber)\n })\n }\n\n /**\n * Check if count is over threshold\n *\n * Checks whether the value is over the configured threshold for the input.\n * If there is no configured threshold, it is set to 0 and this function will\n * always return true.\n *\n * @returns {boolean} true if the current count is over the config.threshold\n * (or no threshold is set)\n */\n isOverThreshold() {\n // No threshold means we're always above threshold so save some computation\n if (!this.config.threshold) {\n return true\n }\n\n // Determine the remaining number of characters/words\n const currentLength = this.count(this.$textarea.value)\n const maxLength = this.maxLength\n\n const thresholdValue = (maxLength * this.config.threshold) / 100\n\n return thresholdValue <= currentLength\n }\n\n /**\n * Handle key up event\n *\n * Update the visible character counter and keep track of when the last update\n * happened for each keypress\n */\n handleKeyUp() {\n this.updateVisibleCountMessage()\n this.lastInputTimestamp = Date.now()\n }\n\n /**\n * Handle focus event\n *\n * Speech recognition software such as Dragon NaturallySpeaking will modify\n * the fields by directly changing its `value`. These changes don't trigger\n * events in JavaScript, so we need to poll to handle when and if they occur.\n *\n * Once the keyup event hasn't been detected for at least 1000 ms (1s), check\n * if the textarea value has changed and update the count message if it has.\n *\n * This is so that the update triggered by the manual comparison doesn't\n * conflict with debounced KeyboardEvent updates.\n */\n handleFocus() {\n this.valueChecker = window.setInterval(() => {\n if (\n !this.lastInputTimestamp ||\n Date.now() - 500 >= this.lastInputTimestamp\n ) {\n this.checkIfValueChanged()\n }\n }, 1000)\n }\n\n /**\n * Handle blur event\n *\n * Stop checking the textarea value once the textarea no longer has focus\n */\n handleBlur() {\n // Cancel value checking on blur\n if (this.valueChecker) {\n window.clearInterval(this.valueChecker)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-character-count'\n\n /**\n * Character count default config\n *\n * @see {@link CharacterCountConfig}\n * @constant\n * @type {CharacterCountConfig}\n */\n static defaults = Object.freeze({\n threshold: 0,\n textareaDescriptionClass: 'nhsuk-character-count__message',\n visibleCountMessageClass: 'nhsuk-character-count__status',\n screenReaderCountMessageClass: 'nhsuk-character-count__sr-status',\n i18n: {\n // Characters\n charactersUnderLimit: {\n one: 'You have %{count} character remaining',\n other: 'You have %{count} characters remaining'\n },\n charactersAtLimit: 'You have 0 characters remaining',\n charactersOverLimit: {\n one: 'You have %{count} character too many',\n other: 'You have %{count} characters too many'\n },\n // Words\n wordsUnderLimit: {\n one: 'You have %{count} word remaining',\n other: 'You have %{count} words remaining'\n },\n wordsAtLimit: 'You have 0 words remaining',\n wordsOverLimit: {\n one: 'You have %{count} word too many',\n other: 'You have %{count} words too many'\n },\n textareaDescription: {\n other: ''\n }\n }\n })\n\n /**\n * Character count config schema\n *\n * @constant\n * @satisfies {Schema<CharacterCountConfig>}\n */\n static schema = Object.freeze({\n properties: {\n maxwords: { type: 'number' },\n maxlength: { type: 'number' },\n threshold: { type: 'number' },\n textareaDescriptionClass: { type: 'string' },\n visibleCountMessageClass: { type: 'string' },\n screenReaderCountMessageClass: { type: 'string' },\n i18n: { type: 'object' }\n },\n anyOf: [\n {\n required: ['maxwords'],\n errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n },\n {\n required: ['maxlength'],\n errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n }\n ]\n })\n}\n\n/**\n * Initialise character count component\n *\n * @deprecated Use {@link createAll | `createAll(CharacterCount, options)`} instead.\n * @param {InitOptions & Partial<CharacterCountConfig>} [options]\n */\nexport function initCharacterCounts(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $characterCounts = $scope?.querySelectorAll(\n `[data-module=\"${CharacterCount.moduleName}\"]`\n )\n\n $characterCounts?.forEach(($root) => {\n new CharacterCount($root, options)\n })\n}\n\n/**\n * Character count config\n *\n * @see {@link CharacterCount.defaults}\n * @typedef {object} CharacterCountConfig\n * @property {number} [maxlength] - The maximum number of characters.\n * If maxwords is provided, the maxlength option will be ignored.\n * @property {number} [maxwords] - The maximum number of words. If maxwords is\n * provided, the maxlength option will be ignored.\n * @property {number} [threshold=0] - The percentage value of the limit at\n * which point the count message is displayed. If this attribute is set, the\n * count message will be hidden by default.\n * @property {string} textareaDescriptionClass - Textarea description class\n * @property {string} visibleCountMessageClass - Visible count message class\n * @property {string} screenReaderCountMessageClass - Screen reader count message class\n * @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations\n */\n\n/**\n * Character count translations\n *\n * @see {@link CharacterCount.defaults.i18n}\n * @see {@link https://github.com/nhsuk/nhsuk-frontend/blob/main/docs/configuration/localisation.md}\n * @typedef {object} CharacterCountTranslations\n *\n * Messages shown to users as they type. It provides feedback on how many words\n * or characters they have remaining or if they are over the limit. This also\n * includes a message used as an accessible description for the textarea.\n * @property {TranslationPluralForms} [charactersUnderLimit] - Message displayed\n * when the number of characters is under the configured maximum, `maxlength`.\n * This message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining characters. This is a pluralised list of messages.\n * @property {string} [charactersAtLimit] - Message displayed when the number of\n * characters reaches the configured maximum, `maxlength`. This message is\n * displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [charactersOverLimit] - Message displayed\n * when the number of characters is over the configured maximum, `maxlength`.\n * This message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining characters. This is a pluralised list of messages.\n * @property {TranslationPluralForms} [wordsUnderLimit] - Message displayed when\n * the number of words is under the configured maximum, `maxlength`. This\n * message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining words. This is a pluralised list of messages.\n * @property {string} [wordsAtLimit] - Message displayed when the number of\n * words reaches the configured maximum, `maxlength`. This message is\n * displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [wordsOverLimit] - Message displayed when\n * the number of words is over the configured maximum, `maxlength`. This\n * message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining words. This is a pluralised list of messages.\n * @property {TranslationPluralForms} [textareaDescription] - Message made\n * available to assistive technologies, if none is already present in the\n * HTML, to describe that the component accepts only a limited amount of\n * content. It is visible on the page when JavaScript is unavailable. The\n * component will replace the `%{count}` placeholder with the value of the\n * `maxlength` or `maxwords` parameter.\n */\n\n/**\n * @import { TranslationPluralForms } from '../../i18n.mjs'\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","/**\n * Validate component config by schema\n *\n * Follows limited examples in JSON schema for wider support in future\n *\n * {@link https://ajv.js.org/json-schema.html#compound-keywords}\n * {@link https://ajv.js.org/packages/ajv-errors.html#single-message}\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @param {Schema<ConfigurationType>} schema - The schema of a component\n * @param {ConfigurationType} config - Component config\n * @returns {string[]} List of validation errors\n */\nexport function validateConfig(schema, config) {\n const validationErrors = []\n\n // Check errors for each schema\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = []\n\n // Check errors for each schema condition\n if (Array.isArray(conditions)) {\n for (const { required, errorMessage } of conditions) {\n if (!required.every((key) => !!config[key])) {\n errors.push(errorMessage) // Missing config key value\n }\n }\n\n // Check one condition passes or add errors\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors)\n }\n }\n }\n\n return validationErrors\n}\n\n/**\n * @import { Schema } from './index.mjs'\n */\n","import { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { toggleConditionalInput } from '../../common/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\n\n/**\n * Checkboxes component\n *\n * Test at {@link http://localhost:3000/nhsuk-frontend/components/checkboxes/with-conditional-content/}\n *\n * @augments {ConfigurableComponent<CheckboxesConfig>}\n */\nexport class Checkboxes extends ConfigurableComponent {\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<CheckboxesConfig>} [config] - Checkboxes config\n */\n constructor($root, config) {\n super($root, config)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Checkboxes,\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId =\n $input.dataset.ariaControls ?? $input.getAttribute('aria-controls')\n\n // Skip checkboxes without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Checkboxes,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to an aria-controls attribute\n // so that the relationship is exposed in the AOM\n if (!$input.hasAttribute('aria-controls')) {\n $input.setAttribute('aria-controls', targetId)\n delete $input.dataset.ariaControls\n }\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this component.\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const { conditionalClass } = this.config\n toggleConditionalInput($input, `${conditionalClass}--hidden`)\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the checkbox group value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const { checkboxExclusiveGroup: exclusiveGroup } = $input.dataset\n\n const selectorGroup = exclusiveGroup\n ? `[data-checkbox-exclusive-group=\"${exclusiveGroup}\"]`\n : `[name=\"${$input.name}\"]`\n\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"]${selectorGroup}`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n\n // Uncheck all with same exclusive group by default, otherwise fall back to\n // GOV.UK Frontend behaviour to uncheck all with the same name attribute\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n this.setInputState($inputWithSameName, false, exclusiveGroup)\n }\n })\n }\n\n /**\n * Uncheck exclusive inputs\n *\n * Find any checkbox inputs with the same checkbox group value and the 'exclusive' behaviour,\n * and uncheck them. This helps prevent someone checking both a regular checkbox and a\n * \"None of these\" checkbox in the same fieldset.\n *\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const { checkboxExclusiveGroup: exclusiveGroup } = $input.dataset\n\n const selectorGroup = exclusiveGroup\n ? `[data-checkbox-exclusive-group=\"${exclusiveGroup}\"]`\n : `[name=\"${$input.name}\"]`\n\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[type=\"checkbox\"][data-checkbox-exclusive]${selectorGroup}`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n\n // Uncheck the exclusive input only. When no group is set, fall back to\n // GOV.UK Frontend behaviour and locate the exclusive input by name\n if (hasSameFormOwner) {\n this.setInputState($exclusiveInput, false, exclusiveGroup)\n }\n })\n }\n\n /**\n * Set input state, optionally for matching exclusive group only\n *\n * @param {HTMLInputElement} $input - Checkbox input\n * @param {boolean} checked - Checkbox checked state\n * @param {string} [exclusiveGroup] - Set state for matching exclusive group only (optional)\n */\n setInputState($input, checked, exclusiveGroup) {\n const { checkboxExclusiveGroup } = $input.dataset\n\n // Skip input when exclusive group does not match\n if (\n exclusiveGroup &&\n checkboxExclusiveGroup &&\n checkboxExclusiveGroup !== exclusiveGroup\n ) {\n return\n }\n\n $input.checked = checked\n this.syncConditionalRevealWithInputState($input)\n }\n\n /**\n * Toggle classes and attributes\n *\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n if ('checkboxExclusive' in $clickedInput.dataset) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-checkboxes'\n\n /**\n * Radios default config\n *\n * @see {@link CheckboxesConfig}\n * @constant\n * @type {CheckboxesConfig}\n */\n static defaults = Object.freeze({\n conditionalClass: 'nhsuk-checkboxes__conditional'\n })\n\n /**\n * Checkboxes config schema\n *\n * @constant\n * @satisfies {Schema<CheckboxesConfig>}\n */\n static schema = Object.freeze({\n properties: {\n conditionalClass: { type: 'string' }\n }\n })\n}\n\n/**\n * Initialise checkboxes component\n *\n * @deprecated Use {@link createAll | `createAll(Checkboxes, options)`} instead.\n * @param {InitOptions & Partial<CheckboxesConfig>} [options]\n */\nexport function initCheckboxes(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $checkboxes = $scope?.querySelectorAll(\n `[data-module=\"${Checkboxes.moduleName}\"]`\n )\n\n $checkboxes?.forEach(($root) => {\n new Checkboxes($root, options)\n })\n}\n\n/**\n * Checkboxes config\n *\n * @typedef {object} CheckboxesConfig\n * @property {string} conditionalClass - Conditionally revealed content class\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { formatErrorMessage, setFocus } from '../../common/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\n\n/**\n * Error summary component\n *\n * Adapted from https://github.com/alphagov/govuk-frontend/blob/v2.13.0/src/components/error-summary/error-summary.js\n *\n * @augments {ConfigurableComponent<ErrorSummaryConfig>}\n */\nexport class ErrorSummary extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<ErrorSummaryConfig>} [config] - Error summary config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n /**\n * Focus the error summary\n */\n if (!this.config.disableAutoFocus) {\n setFocus(this.$root)\n }\n\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Error summary config override\n *\n * @param {Partial<ErrorSummaryConfig>} _datasetConfig - Config specified by dataset\n * @returns {Partial<ErrorSummaryConfig>} Config to override by dataset\n */\n configOverride(_datasetConfig) {\n let configOverrides = /** @type {Partial<ErrorSummaryConfig>} */ ({})\n\n if ('focusOnPageLoad' in this.config) {\n console.warn(\n formatErrorMessage(\n ErrorSummary,\n 'Option `focusOnPageLoad` is deprecated. Use `disableAutoFocus` instead.'\n )\n )\n\n configOverrides.disableAutoFocus = !this.config.focusOnPageLoad\n }\n\n return configOverrides\n }\n\n /**\n * Get associated legend or label\n *\n * Returns the first element that exists from this list:\n *\n * - The `<legend>` associated with the closest `<fieldset>` ancestor, as long\n * as the top of it is no more than half a viewport height away from the\n * bottom of the input\n * - The first `<label>` that is associated with the input using for=\"inputId\"\n * - The closest parent `<label>`\n *\n * @param {Element} $input - The input\n * @returns {Element | null} Associated legend or label, or null if no\n * associated legend or label can be found\n */\n getAssociatedLegendOrLabel($input) {\n const $fieldset = $input.closest('fieldset')\n\n if ($fieldset) {\n const $legends = $fieldset.getElementsByTagName('legend')\n\n if ($legends.length) {\n const $candidateLegend = $legends[0]\n\n // If the input type is radio or checkbox, always use the legend if\n // there is one.\n if (\n $input instanceof HTMLInputElement &&\n ($input.type === 'checkbox' || $input.type === 'radio')\n ) {\n return $candidateLegend\n }\n\n // For other input types, only scroll to the fieldset’s legend (instead\n // of the label associated with the input) if the input would end up in\n // the top half of the screen.\n //\n // This should avoid situations where the input either ends up off the\n // screen, or obscured by a software keyboard.\n const legendTop = $candidateLegend.getBoundingClientRect().top\n const inputRect = $input.getBoundingClientRect()\n\n // If the browser doesn't support Element.getBoundingClientRect().height\n // or window.innerHeight (like IE8), bail and just link to the label.\n if (inputRect.height && window.innerHeight) {\n const inputBottom = inputRect.top + inputRect.height\n\n if (inputBottom - legendTop < window.innerHeight / 2) {\n return $candidateLegend\n }\n }\n }\n }\n\n return (\n document.querySelector(`label[for='${$input.getAttribute('id')}']`) ??\n $input.closest('label')\n )\n }\n\n /**\n * Focus the target element\n *\n * By default, the browser will scroll the target into view. Because our\n * labels or legends appear above the input, this means the user will be\n * presented with an input without any context, as the label or legend will be\n * off the top of the screen.\n *\n * Manually handling the click event, scrolling the question into view and\n * then focussing the element solves this.\n *\n * This also results in the label and/or legend being announced correctly in\n * NVDA (as tested in 2018.3.2) - without this only the field type is\n * announced (e.g. \"Edit, has autocomplete\").\n *\n * @param {EventTarget} $target - Event target\n * @returns {boolean} True if the target was able to be focussed\n */\n focusTarget($target) {\n // If the element that was clicked was not a link, return early\n if (!($target instanceof HTMLAnchorElement)) {\n return false\n }\n\n const inputId = $target.hash.replace('#', '')\n if (!inputId) {\n return false\n }\n\n const $input = document.getElementById(inputId)\n if (!$input) {\n return false\n }\n\n const $legendOrLabel = this.getAssociatedLegendOrLabel($input)\n if (!$legendOrLabel) {\n return false\n }\n\n // Scroll the legend or label into view *before* calling focus on the input\n // to avoid extra scrolling in browsers that don't support `preventScroll`\n // (which at time of writing is most of them...)\n $legendOrLabel.scrollIntoView()\n $input.focus({ preventScroll: true })\n\n return true\n }\n\n /**\n * Click event handler\n *\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $target = event.target\n if ($target && this.focusTarget($target)) {\n event.preventDefault()\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-error-summary'\n\n /**\n * Error summary default config\n *\n * @see {@link ErrorSummaryConfig}\n * @constant\n * @type {ErrorSummaryConfig}\n */\n static defaults = Object.freeze({\n disableAutoFocus: false\n })\n\n /**\n * Error summary config schema\n *\n * @constant\n * @satisfies {Schema<ErrorSummaryConfig>}\n */\n static schema = Object.freeze({\n properties: {\n focusOnPageLoad: { type: 'boolean' }, // Deprecated\n disableAutoFocus: { type: 'boolean' }\n }\n })\n}\n\n/**\n * Initialise error summary component\n *\n * @deprecated Use {@link createAll | `createAll(ErrorSummary, options)`} instead.\n * @param {InitOptions & Partial<ErrorSummaryConfig>} [options]\n */\nexport function initErrorSummary(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $root = $scope?.querySelector(\n `[data-module=\"${ErrorSummary.moduleName}\"]`\n )\n\n if (!$root) {\n return\n }\n\n new ErrorSummary($root, options)\n}\n\n/**\n * Error summary config\n *\n * @see {@link ErrorSummary.defaults}\n * @typedef {object} ErrorSummaryConfig\n * @property {boolean} [focusOnPageLoad=true] - Deprecated. Use `disableAutoFocus` instead.\n * @property {boolean} [disableAutoFocus=false] - If set to `true` the error\n * summary will not be focussed when the page loads.\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'\nimport { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\nimport { I18n } from '../../i18n.mjs'\n\n/**\n * File upload component\n *\n * @augments {ConfigurableComponent<FileUploadConfig>}\n */\nexport class FileUpload extends ConfigurableComponent {\n /**\n * @type {boolean | undefined}\n */\n enteredAnotherElement\n\n /**\n * @param {Element | null} $root - File input element\n * @param {Partial<FileUploadConfig>} [config] - File Upload config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $input = this.$root.querySelector('input')\n\n if (!($input instanceof HTMLInputElement)) {\n throw new ElementError({\n component: FileUpload,\n element: $input,\n expectedType: 'HTMLInputElement',\n identifier: 'Form field (`<input>`)'\n })\n }\n\n if ($input.type !== 'file') {\n throw new ElementError({\n component: FileUpload,\n element: $input,\n identifier: 'Form field (`<input>`)',\n expectedType: 'HTMLInputElement with attribute (`type=\"file\"`)'\n })\n }\n\n this.$input = $input\n\n if (!this.$input.id) {\n throw new ElementError({\n component: FileUpload,\n identifier: 'File input (`<input type=\"file\">`) attribute (`id`)'\n })\n }\n\n this.id = this.$input.id\n\n const {\n i18n,\n dropZoneClass,\n dropButtonClass,\n dropButtonGroupClass,\n dropInstructionClass,\n chooseFilesButtonClass,\n chooseFilesButtonClassList,\n announcementsClass,\n statusClass\n } = this.config\n\n this.i18n = new I18n(i18n, {\n // Read the fallback if necessary rather than have it set in the defaults\n locale: closestAttributeValue(this.$root, 'lang')\n })\n\n const $label = this.findLabel()\n // Add an ID to the label if it doesn't have one already\n // so it can be referenced by `aria-labelledby`\n if (!$label.id) {\n $label.id = `${this.id}-label`\n }\n\n // We need to copy the 'id' of the root element\n // to the new button replacement element\n // so that focus will work in the error summary\n this.$input.id = `${this.id}-input`\n\n // Hide the native input\n this.$input.setAttribute('hidden', '')\n\n // Locate or create the file drop zone\n this.$dropZone = this.$root.classList.contains(dropZoneClass)\n ? this.$root\n : document.createElement('div')\n\n if (this.$root !== this.$dropZone) {\n this.$dropZone.classList.add(dropZoneClass)\n }\n\n // Create the file selection button\n this.$dropButton = document.createElement('button')\n this.$dropButton.classList.add(dropButtonClass)\n this.$dropButton.type = 'button'\n this.$dropButton.id = this.id\n this.$dropButton.classList.add(`${dropButtonClass}--empty`)\n\n // Copy `aria-describedby` if present so hints and errors\n // are associated to the `<button>`\n const ariaDescribedBy = this.$input.getAttribute('aria-describedby')\n if (ariaDescribedBy) {\n this.$dropButton.setAttribute('aria-describedby', ariaDescribedBy)\n }\n\n // Create status element that shows what/how many files are selected\n this.$status = document.createElement('span')\n this.$status.classList.add('nhsuk-body', statusClass)\n this.$status.setAttribute('aria-live', 'polite')\n this.$status.innerText = this.formatStatusMessage(0)\n\n this.$dropButton.appendChild(this.$status)\n\n const $statusComma = document.createElement('span')\n $statusComma.classList.add('nhsuk-u-visually-hidden')\n $statusComma.innerText = ', '\n $statusComma.id = `${this.id}-comma`\n\n this.$dropButton.appendChild($statusComma)\n\n const $dropButtonGroup = document.createElement('span')\n $dropButtonGroup.classList.add(dropButtonGroupClass)\n\n const $chooseFilesButton = document.createElement('span')\n $chooseFilesButton.classList.add(\n 'nhsuk-button',\n chooseFilesButtonClass,\n ...chooseFilesButtonClassList\n )\n $chooseFilesButton.innerText = this.i18n.t('chooseFilesButton')\n\n $dropButtonGroup.appendChild($chooseFilesButton)\n\n // Add a space so the button and instruction read correctly\n // when CSS is disabled\n $dropButtonGroup.append(' ')\n\n const $dropInstruction = document.createElement('span')\n $dropInstruction.classList.add('nhsuk-body', dropInstructionClass)\n $dropInstruction.innerText = this.i18n.t('dropInstruction')\n\n $dropButtonGroup.appendChild($dropInstruction)\n\n this.$dropButton.appendChild($dropButtonGroup)\n this.$dropButton.setAttribute(\n 'aria-labelledby',\n `${$label.id} ${$statusComma.id} ${this.$dropButton.id}`\n )\n this.$dropButton.addEventListener('click', this.onClick.bind(this))\n this.$dropButton.addEventListener('dragover', (event) => {\n // prevent default to allow drop\n event.preventDefault()\n })\n\n // For backwards compatibility with GOV.UK Frontend, optionally replace\n // the native input with the drop zone unless already in the HTML\n if (!this.$dropZone.parentElement) {\n this.$input.parentElement?.insertBefore(this.$dropZone, this.$input)\n this.$dropZone.appendChild(this.$input)\n }\n\n // Assemble these all together\n this.$dropZone.insertAdjacentElement('afterbegin', this.$dropButton)\n\n this.$input.setAttribute('tabindex', '-1')\n this.$input.setAttribute('aria-hidden', 'true')\n\n // Bind change event to the underlying input\n this.$input.addEventListener('change', this.onChange.bind(this))\n\n // Synchronise the `disabled` state between the button and underlying input\n this.updateDisabledState()\n this.observeDisabledState()\n\n // Handle drop zone visibility\n // A live region to announce when users enter or leave the drop zone\n this.$announcements = document.createElement('span')\n this.$announcements.classList.add(\n announcementsClass,\n 'nhsuk-u-visually-hidden'\n )\n this.$announcements.setAttribute('aria-live', 'assertive')\n this.$dropZone.insertAdjacentElement('afterend', this.$announcements)\n\n // if there is no CSS and input is hidden\n // button will need to handle drop event\n this.$dropButton.addEventListener('drop', this.onDrop.bind(this))\n\n // While user is dragging, it gets a little more complex because of Safari.\n // Safari doesn't fill `relatedTarget` on `dragleave` (nor `dragenter`).\n // This means we can't use `relatedTarget` to:\n // - check if the user is still within the wrapper\n // (`relatedTarget` being a descendant of the wrapper)\n // - check if the user is still over the viewport\n // (`relatedTarget` being null if outside)\n\n // Thanks to `dragenter` bubbling, we can listen on the `document` with a\n // single function and update the visibility based on whether we entered a\n // node inside or outside the wrapper.\n document.addEventListener(\n 'dragenter',\n this.updateDropzoneVisibility.bind(this)\n )\n\n // To detect if we're outside the document, we can track if there was a\n // `dragenter` event preceding a `dragleave`. If there wasn't, this means\n // we're outside the document.\n //\n // The order of events is guaranteed by the HTML specs:\n // https://html.spec.whatwg.org/multipage/dnd.html#drag-and-drop-processing-model\n document.addEventListener('dragenter', () => {\n this.enteredAnotherElement = true\n })\n\n document.addEventListener('dragleave', () => {\n if (!this.enteredAnotherElement && !this.$dropButton.disabled) {\n this.hideDraggingState()\n this.$announcements.innerText = this.i18n.t('leftDropZone')\n }\n\n this.enteredAnotherElement = false\n })\n }\n\n /**\n * Updates the visibility of the dropzone as users enters the various elements on the page\n *\n * @param {DragEvent} event - The `dragenter` event\n */\n updateDropzoneVisibility(event) {\n if (this.$dropButton.disabled) {\n return\n }\n\n const { dropButtonClass } = this.config\n\n // DOM interfaces only type `event.target` as `EventTarget`\n // so we first need to make sure it's a `Node`\n if (event.target instanceof Node) {\n if (this.$dropZone.contains(event.target)) {\n if (event.dataTransfer && this.canDrop(event.dataTransfer)) {\n // Only update the class and make the announcement if not already visible\n // to avoid repeated announcements on NVDA (2024.4) + Firefox (133)\n if (\n !this.$dropButton.classList.contains(`${dropButtonClass}--dragging`)\n ) {\n this.showDraggingState()\n this.$announcements.innerText = this.i18n.t('enteredDropZone')\n }\n }\n } else if (\n this.$dropButton.classList.contains(`${dropButtonClass}--dragging`)\n ) {\n // Only hide the dropzone if it is visible to prevent announcing user\n // left the drop zone when they enter the page but haven't reached yet\n // the file upload component\n this.hideDraggingState()\n this.$announcements.innerText = this.i18n.t('leftDropZone')\n }\n }\n }\n\n /**\n * Show the drop zone visually\n */\n showDraggingState() {\n const { dropButtonClass } = this.config\n this.$dropButton.classList.add(`${dropButtonClass}--dragging`)\n }\n\n /**\n * Hides the drop zone visually\n */\n hideDraggingState() {\n const { dropButtonClass } = this.config\n this.$dropButton.classList.remove(`${dropButtonClass}--dragging`)\n }\n\n /**\n * Handles user dropping on the component\n *\n * @param {DragEvent} event - The `dragenter` event\n */\n onDrop(event) {\n event.preventDefault()\n\n if (event.dataTransfer && this.canFillInput(event.dataTransfer)) {\n this.$input.files = event.dataTransfer.files\n\n // Dispatch a `change` event so external code that would rely on the `<input>`\n // dispatching an event when files are dropped still work.\n // Use a `CustomEvent` so our events are distinguishable from browser's native events\n this.$input.dispatchEvent(new CustomEvent('change'))\n\n this.hideDraggingState()\n }\n }\n\n /**\n * Confirms if enhanced `<input>` can be filled with files from the given `DataTransfer`\n *\n * @param {DataTransfer} dataTransfer - The `DataTransfer` being dropped\n * @returns {boolean} Whether the `DataTransfer` contains files, in number matching the `multiple` attribute of the original `<input>`\n */\n canFillInput(dataTransfer) {\n return this.matchesInputCapacity(dataTransfer.files.length)\n }\n\n /**\n * Confirms if the content of a `DataTransfer` dragged over component can be dropped\n *\n * Unfortunately, there's a certain level of uncertainty in Safari which does not\n * even provide a list of `items` while dragging (and seems to even miss the `types` sometimes)\n *\n * @param {DataTransfer} dataTransfer - The `DataTransfer` being dragged\n * @returns {boolean} Whether the `DataTransfer` looks OK for filling the input, false otherwise\n */\n canDrop(dataTransfer) {\n // If the browser is kind enough to give a list of items, we'll use that as source of truth\n if (dataTransfer.items.length) {\n return this.matchesInputCapacity(countFileItems(dataTransfer.items))\n }\n\n // If we have some type information, we'll use that\n if (dataTransfer.types.length) {\n return dataTransfer.types.includes('Files')\n }\n\n // If we have nothing to go by, we'll assume things are OK\n // until we have a more accurate picture inside the `drop` event\n return true\n }\n\n /**\n * Confirms the given number of files matches that allowed by the enhanced `<input>`\n *\n * @param {number} numberOfFiles - The number of files\n * @returns {boolean} Whether the enhanced `<input>` can accept that number of files\n */\n matchesInputCapacity(numberOfFiles) {\n if (this.$input.multiple) {\n return numberOfFiles > 0\n }\n\n return numberOfFiles === 1\n }\n\n /**\n * Check if the value of the underlying input has changed\n */\n onChange() {\n const { dropButtonClass } = this.config\n const { files } = this.$input\n\n if (!files?.length) {\n // If there are no files, show the default selection text\n this.$status.innerText = this.formatStatusMessage(0)\n this.$dropButton.classList.add(`${dropButtonClass}--empty`)\n } else {\n if (\n // If there is 1 file, just show the file name\n files.length === 1\n ) {\n this.$status.innerText = files[0].name\n } else {\n // Otherwise, tell the user how many files are selected\n this.$status.innerText = this.formatStatusMessage(files.length)\n }\n\n this.$dropButton.classList.remove(`${dropButtonClass}--empty`)\n }\n }\n\n /**\n * Formats the message shown to users according to files chosen\n *\n * @param {number} fileCount - The number of files chosen\n * @returns {string} Status message\n */\n formatStatusMessage(fileCount) {\n if (fileCount === 0) {\n return this.i18n.t('noFileChosen')\n }\n\n return this.i18n.t('multipleFilesChosen', { count: fileCount })\n }\n\n /**\n * Looks up the `<label>` element associated to the field\n *\n * @returns {HTMLElement} The `<label>` element associated to the field\n * @throws {ElementError} If the `<label>` cannot be found\n */\n findLabel() {\n // Use `label` in the selector so TypeScript knows the type of `HTMLElement`\n const $label = document.querySelector(`label[for=\"${this.$input.id}\"]`)\n\n if (!$label) {\n throw new ElementError({\n component: FileUpload,\n identifier: `Field label (\\`<label for=${this.$input.id}>\\`)`\n })\n }\n\n return $label\n }\n\n /**\n * When the button is clicked, emulate clicking the actual, hidden file input\n */\n onClick() {\n this.$input.click()\n }\n\n /**\n * Create a mutation observer to check if the input's attributes altered.\n */\n observeDisabledState() {\n const observer = new MutationObserver((mutationList) => {\n for (const mutation of mutationList) {\n if (\n mutation.type === 'attributes' &&\n mutation.attributeName === 'disabled'\n ) {\n this.updateDisabledState()\n }\n }\n })\n\n observer.observe(this.$input, {\n attributes: true\n })\n }\n\n /**\n * Synchronise the `disabled` state between the input and replacement button.\n */\n updateDisabledState() {\n const { dropZoneClass } = this.config\n\n const disabledStateClass = this.$root.classList.contains(dropZoneClass)\n ? `${dropZoneClass}--disabled`\n : `${FileUpload.moduleName}--disabled`\n\n this.$dropButton.disabled = this.$input.disabled\n this.$root.classList.toggle(disabledStateClass, this.$dropButton.disabled)\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'nhsuk-file-upload'\n\n /**\n * File upload default config\n *\n * @see {@link FileUploadConfig}\n * @constant\n * @type {FileUploadConfig}\n */\n static defaults = Object.freeze({\n dropZoneClass: 'nhsuk-file-upload__drop-zone',\n dropButtonClass: 'nhsuk-file-upload__drop-button',\n dropButtonGroupClass: 'nhsuk-file-upload__drop-button-group',\n dropInstructionClass: 'nhsuk-file-upload__drop-instruction',\n chooseFilesButtonClass: 'nhsuk-file-upload__choose-files-button',\n chooseFilesButtonClassList: ['nhsuk-button--secondary'],\n announcementsClass: 'nhsuk-file-upload__announcements',\n statusClass: 'nhsuk-file-upload__status',\n i18n: {\n chooseFilesButton: 'Choose file',\n dropInstruction: 'or drop file',\n noFileChosen: 'No file chosen',\n multipleFilesChosen: {\n // the 'one' string isn't used as the component displays the filename\n // instead, however it's here for coverage's sake\n one: '%{count} file chosen',\n other: '%{count} files chosen'\n },\n enteredDropZone: 'Entered drop zone',\n leftDropZone: 'Left drop zone'\n }\n })\n\n /**\n * File upload config schema\n *\n * @constant\n * @satisfies {Schema<FileUploadConfig>}\n */\n static schema = Object.freeze({\n properties: {\n dropZoneClass: { type: 'string' },\n dropButtonClass: { type: 'string' },\n dropButtonGroupClass: { type: 'string' },\n dropInstructionClass: { type: 'string' },\n chooseFilesButtonClass: { type: 'string' },\n chooseFilesButtonClassList: { type: 'array' },\n announcementsClass: { type: 'string' },\n statusClass: { type: 'string' },\n i18n: { type: 'object' }\n }\n })\n}\n\n/**\n * Counts the number of `DataTransferItem` whose kind is `file`\n *\n * @param {DataTransferItemList} list - The list\n * @returns {number} The number of items whose kind is `file` in the list\n */\nfunction countFileItems(list) {\n let result = 0\n\n // `DataTransferItemList` is not iterable\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < list.length; i++) {\n if (list[i].kind === 'file') {\n result++\n }\n }\n return result\n}\n\n/**\n * Initialise file upload component\n *\n * @deprecated Use {@link createAll | `createAll(FileUpload, options)`} instead.\n * @param {InitOptions & Partial<FileUploadConfig>} [options]\n */\nexport function initFileUploads(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $fileUploads = $scope?.querySelectorAll(\n `[data-module=\"${FileUpload.moduleName}\"]`\n )\n\n $fileUploads?.forEach(($root) => {\n new FileUpload($root, options)\n })\n}\n\n/**\n * File upload config\n *\n * @see {@link FileUpload.defaults}\n * @typedef {object} FileUploadConfig\n * @property {string} dropZoneClass - Drop zone class\n * @property {string} dropButtonClass - Drop button class\n * @property {string} dropButtonGroupClass - Drop button group class\n * @property {string} dropInstructionClass - Drop instruction class\n * @property {string} chooseFilesButtonClass - Choose files button class\n * @property {string[]} chooseFilesButtonClassList - Choose files button modifier classes\n * @property {string} announcementsClass - Announcements class\n * @property {string} statusClass - Status class\n * @property {FileUploadTranslations} [i18n=FileUpload.defaults.i18n] - File upload translations\n */\n\n/**\n * File upload translations\n *\n * @see {@link FileUpload.defaults.i18n}\n * @typedef {object} FileUploadTranslations\n *\n * Messages used by the component\n * @property {string} [chooseFilesButton] - The text of the button that opens the file picker\n * @property {string} [dropInstruction] - The text informing users they can drop files\n * @property {TranslationPluralForms} [multipleFilesChosen] - The text displayed when multiple files\n * have been chosen by the user\n * @property {string} [noFileChosen] - The text to displayed when no file has been chosen by the user\n * @property {string} [enteredDropZone] - The text announced by assistive technology\n * when user drags files and enters the drop zone\n * @property {string} [leftDropZone] - The text announced by assistive technology\n * when user drags files and leaves the drop zone without dropping\n */\n\n/**\n * @import { Schema } from '../../common/configuration/index.mjs'\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { TranslationPluralForms } from '../../i18n.mjs'\n */\n","import { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\n\n/**\n * Header component\n *\n * @augments {ConfigurableComponent<HeaderConfig>}\n */\nexport class Header extends ConfigurableComponent {\n /** @type {HTMLElement | null} */\n $navigation = null\n\n /** @type {HTMLElement | null} */\n $navigationList = null\n\n /** @type {NodeListOf<HTMLElement> | null} */\n $navigationItems = null\n\n /** @type {HTMLElement | null} */\n $menu = null\n\n /** @type {HTMLButtonElement | null} */\n $menuToggle = null\n\n /** @type {HTMLElement | null} */\n $menuList = null\n\n width = 0\n\n /**\n * @type {{ element: HTMLElement, right: number }[]}\n */\n breakpoints = []\n\n /**\n * @type {number | null}\n */\n updateNavigationTimer = null\n\n menuIsEnabled = false\n menuIsOpen = false\n\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<HeaderConfig>} [config] - Header config\n */\n constructor($root, config) {\n super($root, config)\n\n const {\n navigationClass,\n navigationListClass,\n navigationItemClass,\n menuClass,\n menuToggleClass\n } = this.config\n\n const $navigation = this.$root.querySelector(`.${navigationClass}`)\n const $navigationList = this.$root.querySelector(`.${navigationListClass}`)\n\n const $navigationItems = /** @type {NodeListOf<HTMLElement>} */ (\n this.$root.querySelectorAll(`.${navigationItemClass}`)\n )\n\n const $menu = this.$root.querySelector(`.${menuClass}`)\n const $menuToggle = this.$root.querySelector(`.${menuToggleClass}`)\n\n // Check for navigation (optional)\n if ($navigation) {\n if (!($navigation instanceof HTMLElement)) {\n throw new ElementError({\n component: Header,\n identifier: `Navigation (\\`<nav class=\"${navigationClass}\">\\`)`\n })\n }\n\n if (!$navigationList || !($navigationList instanceof HTMLElement)) {\n throw new ElementError({\n component: Header,\n identifier: `List (\\`<ul class=\"${navigationListClass}\">\\`)`\n })\n }\n\n if (!$navigationItems.length) {\n throw new ElementError({\n component: Header,\n identifier: `List items (\\`<li class=\"${navigationItemClass}\">\\`)`\n })\n }\n\n if (!$menu || !($menu instanceof HTMLElement)) {\n throw new ElementError({\n component: Header,\n identifier: `Menu item (\\`<li class=\"${menuClass}\" hidden>\\`)`\n })\n }\n\n if (!$menuToggle || !($menuToggle instanceof HTMLButtonElement)) {\n throw new ElementError({\n component: Header,\n identifier: `Menu button (\\`<button class=\"${menuToggleClass}\">\\`)`,\n expectedType: 'HTMLButtonElement'\n })\n }\n\n this.$navigation = $navigation\n this.$navigationList = $navigationList\n this.$navigationItems = $navigationItems\n this.$menu = $menu\n this.$menuToggle = $menuToggle\n this.$menuList = document.createElement('ul')\n }\n\n // Save bound functions so we can remove event listeners when unnecessary\n this.handleEscapeKey = this.onEscapeKey.bind(this)\n this.handleUpdateNavigation = this.updateNavigation.bind(this)\n this.handleToggleMenu = this.toggleMenu.bind(this)\n\n this.setupNavigation()\n this.updateNavigation()\n }\n\n /**\n * Reset navigation\n *\n * Calculate available space by summing the width of each navigation item\n */\n resetNavigation() {\n const { $menu, $navigationList } = this\n if (!$menu || !$navigationList) {\n return\n }\n\n let right = 0\n\n // Reset and calculate widths on every resize\n this.breakpoints.forEach((breakpoint) => {\n $navigationList.insertBefore(breakpoint.element, $menu)\n\n // Calculate widths\n right += breakpoint.element.offsetWidth\n breakpoint.right = right\n })\n\n // Reset space for menu button\n this.width = $navigationList.offsetWidth\n }\n\n /**\n * Add the breakpoints with default positions\n */\n setupNavigation() {\n const { $navigationItems } = this\n\n // Skip with no navigation items\n if (!$navigationItems) {\n return\n }\n\n $navigationItems.forEach((element) => {\n this.breakpoints.push({ element, right: 0 })\n })\n\n // Add resize listener for next update\n window.addEventListener('resize', () => {\n if (this.updateNavigationTimer) {\n window.clearTimeout(this.updateNavigationTimer)\n }\n\n this.updateNavigationTimer = window.setTimeout(\n this.handleUpdateNavigation,\n 100\n )\n })\n }\n\n /**\n * Add the menu to the DOM\n */\n setupMenu() {\n const { $menu, $menuList } = this\n const { menuListClass } = this.config\n\n // Skip with no menu or when already appended\n if (!$menu || !$menuList || $menuList.parentElement) {\n return\n }\n\n $menuList.classList.add(menuListClass)\n $menuList.setAttribute('hidden', '')\n $menu.appendChild($menuList)\n }\n\n /**\n * Enable the menu\n */\n enableMenu() {\n const { $menu, $menuToggle } = this\n\n // Skip with no menu or when already enabled\n if (!$menu || !$menuToggle || this.menuIsEnabled) {\n return\n }\n\n this.menuIsEnabled = true\n $menu.removeAttribute('hidden')\n\n // Add click listener to toggle menu\n $menuToggle.addEventListener('click', this.handleToggleMenu)\n }\n\n /**\n * Disable the menu\n */\n disableMenu() {\n const { $menu, $menuToggle } = this\n\n // Skip with no menu or when already disabled\n if (!$menu || !$menuToggle || !this.menuIsEnabled) {\n return\n }\n\n this.closeMenu()\n this.menuIsEnabled = false\n $menu.setAttribute('hidden', '')\n\n // Remove click listener from toggle menu\n $menuToggle.removeEventListener('click', this.handleToggleMenu)\n }\n\n /**\n * Close the menu\n *\n * Closes the menu and updates accessibility state.\n *\n * Removes the bottom border from the navigation\n */\n closeMenu() {\n const { $menuList, $menuToggle, $navigation } = this\n\n // Skip with no menu or when already closed\n if (\n !$navigation ||\n !$menuList ||\n !$menuToggle ||\n !this.menuIsEnabled ||\n !this.menuIsOpen\n ) {\n return\n }\n\n this.menuIsOpen = false\n $menuList.setAttribute('hidden', '')\n $menuToggle.setAttribute('aria-expanded', 'false')\n $navigation.style.removeProperty('border-bottom-width')\n\n // Remove escape key listener to close menu\n document.removeEventListener('keydown', this.handleEscapeKey)\n }\n\n /**\n * Escape key handler\n *\n * This function is called when the user\n * presses the escape key to close the menu.\n *\n * @param {KeyboardEvent} event - Key press event\n */\n onEscapeKey(event) {\n if (event.key === 'Escape') {\n this.closeMenu()\n }\n }\n\n /**\n * Open the menu\n *\n * Opens the menu and updates accessibility state.\n *\n * The menu is absolutely positioned, so it adds a border\n * to the bottom of the navigation to prevent it from overlapping\n *\n * Adds event listeners for the close button,\n */\n openMenu() {\n const { $menuList, $menuToggle, $navigation } = this\n\n // Skip with no menu or when already open\n if (\n !$navigation ||\n !$menuList ||\n !$menuToggle ||\n !this.menuIsEnabled ||\n this.menuIsOpen\n ) {\n return\n }\n\n this.menuIsOpen = true\n $menuList.removeAttribute('hidden')\n $menuToggle.setAttribute('aria-expanded', 'true')\n $navigation.style.setProperty(\n 'border-bottom-width',\n `${$menuList.offsetHeight}px`\n )\n\n // Add escape key listener to close menu\n document.addEventListener('keydown', this.handleEscapeKey)\n }\n\n /**\n * Handle menu button click\n *\n * Toggles the menu between open and closed\n */\n toggleMenu() {\n if (!this.menuIsEnabled) {\n return\n }\n\n if (this.menuIsOpen) {\n this.closeMenu()\n } else {\n this.openMenu()\n }\n }\n\n /**\n * Update navigation for the available space\n *\n * Moves all items that overflow the available space into the menu\n */\n updateNavigation() {\n this.resetNavigation()\n\n // Check for items that overflow\n let menuItems = this.breakpoints.filter((breakpoint) => {\n return breakpoint.right > this.width\n })\n\n // Disable menu if empty\n if (!menuItems.length) {\n this.disableMenu()\n return\n }\n\n this.setupMenu()\n this.enableMenu()\n\n const { $menu, $menuList, $navigation } = this\n\n // Skip when no menu or menu list\n if (!$menu || !$menuList || !$navigation) {\n return\n }\n\n // Subtract space for menu button\n this.width -= $menu.offsetWidth\n\n // Move items based on available width\n this.breakpoints.forEach((breakpoint) => {\n if (breakpoint.right > this.width) {\n $menuList.insertAdjacentElement('beforeend', breakpoint.element)\n }\n })\n\n // Update menu height if open\n if (this.menuIsOpen) {\n $navigation.style.setProperty(\n 'border-bottom-width',\n `${$menuList.offsetHeight}px`\n )\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-header'\n\n /**\n * Tabs default config\n *\n * @see {@link HeaderConfig}\n * @constant\n * @type {HeaderConfig}\n */\n static defaults = Object.freeze({\n navigationClass: 'nhsuk-header__navigation',\n navigationListClass: 'nhsuk-header__navigation-list',\n navigationItemClass: 'nhsuk-header__navigation-item',\n menuClass: 'nhsuk-header__menu',\n menuToggleClass: 'nhsuk-header__menu-toggle',\n menuListClass: 'nhsuk-header__menu-list'\n })\n\n /**\n * Tabs config schema\n *\n * @constant\n * @satisfies {Schema<HeaderConfig>}\n */\n static schema = Object.freeze({\n properties: {\n navigationClass: { type: 'string' },\n navigationListClass: { type: 'string' },\n navigationItemClass: { type: 'string' },\n menuClass: { type: 'string' },\n menuToggleClass: { type: 'string' },\n menuListClass: { type: 'string' }\n }\n })\n}\n\n/**\n * Initialise header component\n *\n * @deprecated Use {@link createAll | `createAll(Header, options)`} instead.\n * @param {InitOptions & Partial<HeaderConfig>} [options]\n */\nexport function initHeader(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $root = $scope?.querySelector(`[data-module=\"${Header.moduleName}\"]`)\n\n if (!$root) {\n return\n }\n\n new Header($root, options)\n}\n\n/**\n * Header config\n *\n * @typedef {object} HeaderConfig\n * @property {string} navigationClass - Navigation class\n * @property {string} navigationListClass - Navigation list class\n * @property {string} navigationItemClass - Navigation item class\n * @property {string} menuClass - Menu class\n * @property {string} menuToggleClass - Menu toggle button class\n * @property {string} menuListClass - Menu list class\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { setFocus } from '../../common/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\n\n/**\n * Notification banner component\n *\n * Adapted from https://github.com/alphagov/govuk-frontend/blob/v5.10.2/packages/govuk-frontend/src/govuk/components/notification-banner/notification-banner.mjs\n *\n * @augments {ConfigurableComponent<NotificationBannerConfig>}\n */\nexport class NotificationBanner extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<NotificationBannerConfig>} [config] - Notification banner config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n /**\n * Focus the notification banner\n *\n * If `role=\"alert\"` is set, focus the element to help some assistive\n * technologies prioritise announcing it.\n *\n * You can turn off the auto-focus functionality by setting\n * `data-disable-auto-focus=\"true\"` in the component HTML. You might wish to\n * do this based on user research findings, or to avoid a clash with another\n * element which should be focused when the page loads.\n */\n if (\n this.$root.getAttribute('role') === 'alert' &&\n !this.config.disableAutoFocus\n ) {\n setFocus(this.$root)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'nhsuk-notification-banner'\n\n /**\n * Notification banner default config\n *\n * @see {@link NotificationBannerConfig}\n * @constant\n * @type {NotificationBannerConfig}\n */\n static defaults = Object.freeze({\n disableAutoFocus: false\n })\n\n /**\n * Notification banner config schema\n *\n * @constant\n * @satisfies {Schema<NotificationBannerConfig>}\n */\n static schema = Object.freeze({\n properties: {\n disableAutoFocus: { type: 'boolean' }\n }\n })\n}\n\n/**\n * Initialise notification banner component\n *\n * @deprecated Use {@link createAll | `createAll(NotificationBanner, options)`} instead.\n * @param {InitOptions & Partial<NotificationBannerConfig>} [options]\n */\nexport function initNotificationBanners(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $notificationBanners = $scope?.querySelectorAll(\n `[data-module=\"${NotificationBanner.moduleName}\"]`\n )\n\n $notificationBanners?.forEach(($notificationBanner) => {\n new NotificationBanner($notificationBanner, options)\n })\n}\n\n/**\n * Notification banner config\n *\n * @typedef {object} NotificationBannerConfig\n * @property {boolean} [disableAutoFocus=false] - If set to `true` the\n * notification banner will not be focussed when the page loads. This only\n * applies if the component has a `role` of `alert` – in other cases the\n * component will not be focused on page load, regardless of this option.\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'\nimport { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\nimport { I18n } from '../../i18n.mjs'\n\n/**\n * Password input component\n *\n * @augments {ConfigurableComponent<PasswordInputConfig>}\n */\nexport class PasswordInput extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<PasswordInputConfig>} [config] - Password input config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $input = this.$root.querySelector('.nhsuk-js-password-input-input')\n if (!($input instanceof HTMLInputElement)) {\n throw new ElementError({\n component: PasswordInput,\n element: $input,\n expectedType: 'HTMLInputElement',\n identifier: 'Form field (`.nhsuk-js-password-input-input`)'\n })\n }\n\n if ($input.type !== 'password') {\n throw new ElementError({\n component: PasswordInput,\n element: $input,\n expectedType: 'HTMLInputElement with attribute (`type=\"password\"`)',\n identifier: 'Form field (`.nhsuk-js-password-input-input`)'\n })\n }\n\n const $showHideButton = this.$root.querySelector(\n '.nhsuk-js-password-input-toggle'\n )\n if (!($showHideButton instanceof HTMLButtonElement)) {\n throw new ElementError({\n component: PasswordInput,\n element: $showHideButton,\n expectedType: 'HTMLButtonElement',\n identifier: 'Button (`.nhsuk-js-password-input-toggle`)'\n })\n }\n\n if ($showHideButton.type !== 'button') {\n throw new ElementError({\n component: PasswordInput,\n element: $showHideButton,\n expectedType: 'HTMLButtonElement with type=\"button\"',\n identifier: 'Button (`.nhsuk-js-password-input-toggle`)'\n })\n }\n\n this.$input = $input\n this.$showHideButton = $showHideButton\n\n const { i18n, screenReaderStatusMessageClass } = this.config\n\n this.i18n = new I18n(i18n, {\n // Read the fallback if necessary rather than have it set in the defaults\n locale: closestAttributeValue(this.$root, 'lang')\n })\n\n // Show the toggle button element\n this.$showHideButton.removeAttribute('hidden')\n\n // Create and append the status text for screen readers.\n // This is injected between the input and button so that users get a sensible reading order if\n // moving through the page content linearly:\n // [password input] -> [your password is visible/hidden] -> [show/hide password]\n this.$screenReaderStatusMessage = document.createElement('div')\n this.$screenReaderStatusMessage.setAttribute('aria-live', 'polite')\n this.$screenReaderStatusMessage.classList.add(\n screenReaderStatusMessageClass,\n 'nhsuk-u-visually-hidden'\n )\n\n this.$input.insertAdjacentElement(\n 'afterend',\n this.$screenReaderStatusMessage\n )\n\n // Bind toggle button\n this.$showHideButton.addEventListener('click', this.toggle.bind(this))\n\n // Bind event to revert the password visibility to hidden\n if (this.$input.form) {\n this.$input.form.addEventListener('submit', () => this.hide())\n }\n\n // If the page is restored from bfcache and the password is visible, hide it again\n window.addEventListener('pageshow', (event) => {\n if (event.persisted && this.$input.type !== 'password') {\n this.hide()\n }\n })\n\n // Default the component to having the password hidden.\n this.hide()\n }\n\n /**\n * Toggle the visibility of the password input\n *\n * @param {MouseEvent} event - Click event\n */\n toggle(event) {\n event.preventDefault()\n\n // If on this click, the field is type=\"password\", show the value\n if (this.$input.type === 'password') {\n this.show()\n return\n }\n\n // Otherwise, hide it\n // Being defensive - hiding should always be the default\n this.hide()\n }\n\n /**\n * Show the password input value in plain text\n */\n show() {\n this.setType('text')\n }\n\n /**\n * Hide the password input value\n */\n hide() {\n this.setType('password')\n }\n\n /**\n * Set the password input type\n *\n * @param {'text' | 'password'} type - Input type\n */\n setType(type) {\n if (type === this.$input.type) {\n return\n }\n\n // Update input type\n this.$input.setAttribute('type', type)\n\n const isHidden = type === 'password'\n const prefixButton = isHidden ? 'show' : 'hide'\n const prefixStatus = isHidden ? 'passwordHidden' : 'passwordShown'\n\n // Update button text\n this.$showHideButton.innerText = this.i18n.t(`${prefixButton}Password`)\n\n // Update button aria-label\n this.$showHideButton.setAttribute(\n 'aria-label',\n this.i18n.t(`${prefixButton}PasswordAriaLabel`)\n )\n\n // Update status change text\n this.$screenReaderStatusMessage.innerText = this.i18n.t(\n `${prefixStatus}Announcement`\n )\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-password-input'\n\n /**\n * Password input default config\n *\n * @see {@link PasswordInputConfig}\n * @constant\n * @type {PasswordInputConfig}\n */\n static defaults = Object.freeze({\n screenReaderStatusMessageClass: 'nhsuk-password-input__sr-status',\n i18n: {\n showPassword: 'Show',\n hidePassword: 'Hide',\n showPasswordAriaLabel: 'Show password',\n hidePasswordAriaLabel: 'Hide password',\n passwordShownAnnouncement: 'Your password is visible',\n passwordHiddenAnnouncement: 'Your password is hidden'\n }\n })\n\n /**\n * Password input config schema\n *\n * @constant\n * @satisfies {Schema<PasswordInputConfig>}\n */\n static schema = Object.freeze({\n properties: {\n screenReaderStatusMessageClass: { type: 'string' },\n i18n: { type: 'object' }\n }\n })\n}\n\n/**\n * Initialise password input component\n *\n * @deprecated Use {@link createAll | `createAll(PasswordInput, options)`} instead.\n * @param {InitOptions & Partial<PasswordInputConfig>} [options]\n */\nexport function initPasswordInputs(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $passwordInputs = $scope?.querySelectorAll(\n `[data-module=\"${PasswordInput.moduleName}\"]`\n )\n\n $passwordInputs?.forEach(($root) => {\n new PasswordInput($root, options)\n })\n}\n\n/**\n * Password input config\n *\n * @typedef {object} PasswordInputConfig\n * @property {string} screenReaderStatusMessageClass - Screen reader status message class\n * @property {PasswordInputTranslations} [i18n=PasswordInput.defaults.i18n] - Password input translations\n */\n\n/**\n * Password input translations\n *\n * @see {@link PasswordInput.defaults.i18n}\n * @typedef {object} PasswordInputTranslations\n *\n * Messages displayed to the user indicating the state of the show/hide toggle.\n * @property {string} [showPassword] - Visible text of the button when the\n * password is currently hidden. Plain text only.\n * @property {string} [hidePassword] - Visible text of the button when the\n * password is currently visible. Plain text only.\n * @property {string} [showPasswordAriaLabel] - aria-label of the button when\n * the password is currently hidden. Plain text only.\n * @property {string} [hidePasswordAriaLabel] - aria-label of the button when\n * the password is currently visible. Plain text only.\n * @property {string} [passwordShownAnnouncement] - Screen reader\n * announcement to make when the password has just become visible.\n * Plain text only.\n * @property {string} [passwordHiddenAnnouncement] - Screen reader\n * announcement to make when the password has just been hidden.\n * Plain text only.\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { toggleConditionalInput } from '../../common/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\n\n/**\n * Radios component\n *\n * Test at {@link http://localhost:3000/nhsuk-frontend/components/radios/with-conditional-content/}\n *\n * @augments {ConfigurableComponent<RadiosConfig>}\n */\nexport class Radios extends ConfigurableComponent {\n /**\n * Radios can be associated with a 'conditionally revealed' content block –\n * for example, a radio for 'Phone' could reveal an additional form field for\n * the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the radio state.\n *\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<RadiosConfig>} [config] - Radios config\n */\n constructor($root, config) {\n super($root, config)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"radio\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Radios,\n identifier: 'Form inputs (`<input type=\"radio\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId =\n $input.dataset.ariaControls ?? $input.getAttribute('aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Radios,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to an aria-controls attribute\n // so that the relationship is exposed in the AOM\n if (!$input.hasAttribute('aria-controls')) {\n $input.setAttribute('aria-controls', targetId)\n delete $input.dataset.ariaControls\n }\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all radio buttons in this component.\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @param {HTMLInputElement} $input - Radio input\n */\n syncConditionalRevealWithInputState($input) {\n const { conditionalClass } = this.config\n toggleConditionalInput($input, `${conditionalClass}--hidden`)\n }\n\n /**\n * Toggle classes and attributes\n *\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't radio buttons\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'radio'\n ) {\n return\n }\n\n // We only need to consider radios with conditional reveals, which will have\n // aria-controls attributes.\n const $allInputs = document.querySelectorAll(\n 'input[type=\"radio\"][aria-controls]'\n )\n\n const $clickedInputForm = $clickedInput.form\n const $clickedInputName = $clickedInput.name\n\n $allInputs.forEach(($input) => {\n const hasSameFormOwner = $input.form === $clickedInputForm\n const hasSameName = $input.name === $clickedInputName\n\n if (hasSameName && hasSameFormOwner) {\n this.syncConditionalRevealWithInputState($input)\n }\n })\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-radios'\n\n /**\n * Radios default config\n *\n * @see {@link RadiosConfig}\n * @constant\n * @type {RadiosConfig}\n */\n static defaults = Object.freeze({\n conditionalClass: 'nhsuk-radios__conditional'\n })\n\n /**\n * Radios config schema\n *\n * @constant\n * @satisfies {Schema<RadiosConfig>}\n */\n static schema = Object.freeze({\n properties: {\n conditionalClass: { type: 'string' }\n }\n })\n}\n\n/**\n * Initialise radios component\n *\n * @deprecated Use {@link createAll | `createAll(Radios, options)`} instead.\n * @param {InitOptions & Partial<RadiosConfig>} [options]\n */\nexport function initRadios(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $radios = $scope?.querySelectorAll(\n `[data-module=\"${Radios.moduleName}\"]`\n )\n\n $radios?.forEach(($root) => {\n new Radios($root, options)\n })\n}\n\n/**\n * Radios config\n *\n * @typedef {object} RadiosConfig\n * @property {string} conditionalClass - Conditionally revealed content class\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { setFocus } from '../../common/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\n\nconst _self =\n typeof globalThis !== 'undefined'\n ? globalThis // Modern browsers, Node.js\n : self // Old browsers, web workers\n\n/**\n * Skip link component\n *\n * When using VoiceOver on iOS, focus remains on the skip link anchor\n * when selected so the next focusable element is not at the jumped to area.\n *\n * @augments {ConfigurableComponent<SkipLinkConfig, HTMLAnchorElement>}\n */\nexport class SkipLink extends ConfigurableComponent {\n static elementType = _self.HTMLAnchorElement\n\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<SkipLinkConfig>} [config] - Skip link config\n */\n constructor($root, config) {\n super($root, config)\n\n const hash = this.$root.hash\n const href = this.$root.getAttribute('href') ?? ''\n\n // Return early for external URLs or links to other pages\n if (\n this.$root.origin !== window.location.origin ||\n this.$root.pathname !== window.location.pathname\n ) {\n return\n }\n\n const linkedElementId = hash.replace('#', '')\n\n // Check link path matching current page\n if (!linkedElementId) {\n throw new ElementError({\n component: SkipLink,\n identifier: `Target link (\\`href=\"${href}\"\\`) hash fragment`\n })\n }\n\n const $linkedElement = document.getElementById(linkedElementId)\n\n // Check for linked element\n if (!$linkedElement) {\n throw new ElementError({\n component: SkipLink,\n element: $linkedElement,\n identifier: `Target content (\\`id=\"${linkedElementId}\"\\`)`\n })\n }\n\n /**\n * Focus the linked element on click\n *\n * Adds a helper CSS class to hide native focus styles,\n * but removes it on blur to restore native focus styles\n */\n this.$root.addEventListener('click', () => {\n const { focusedElementClassList } = this.config\n\n setFocus($linkedElement, {\n onBeforeFocus() {\n $linkedElement.classList.add(...focusedElementClassList)\n },\n onBlur() {\n $linkedElement.classList.remove(...focusedElementClassList)\n }\n })\n })\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-skip-link'\n\n /**\n * Skip link default config\n *\n * @see {@link SkipLinkConfig}\n * @constant\n * @type {SkipLinkConfig}\n */\n static defaults = Object.freeze({\n focusedElementClassList: ['nhsuk-skip-link-focused-element']\n })\n\n /**\n * Skip link config schema\n *\n * @constant\n * @satisfies {Schema<SkipLinkConfig>}\n */\n static schema = Object.freeze({\n properties: {\n focusedElementClassList: { type: 'array' }\n }\n })\n}\n\n/**\n * Initialise skip link component\n *\n * @deprecated Use {@link createAll | `createAll(SkipLink, options)`} instead.\n * @param {InitOptions & Partial<SkipLinkConfig>} [options]\n */\nexport function initSkipLinks(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $skipLinks = $scope?.querySelectorAll(\n `[data-module=\"${SkipLink.moduleName}\"]`\n )\n\n $skipLinks?.forEach(($root) => {\n new SkipLink($root, options)\n })\n}\n\n/**\n * Skip link config\n *\n * @typedef {object} SkipLinkConfig\n * @property {string[]} focusedElementClassList - Focused element class list\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","/* eslint-disable @typescript-eslint/no-deprecated */\n\nimport { normaliseOptions } from '../../common/configuration/index.mjs'\nimport { getBreakpoint } from '../../common/index.mjs'\nimport { ConfigurableComponent } from '../../configurable-component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\n\n/**\n * Tabs component\n *\n * @augments {ConfigurableComponent<TabsConfig>}\n */\nexport class Tabs extends ConfigurableComponent {\n changingHash = false\n\n /**\n * @type {string | undefined}\n * @deprecated Use {@link Tabs.panelClass} instead.\n */\n jsHiddenClass\n\n /**\n * @type {MediaQueryList | null}\n */\n mql = null\n\n /**\n * @param {Element | null} $root - HTML element to use for component\n * @param {Partial<TabsConfig>} [config] - Tabs config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const { listClass, listItemClass, tabClass } = this.config\n\n const $tabs = this.$root.querySelectorAll(`a.${tabClass}`)\n if (!$tabs.length) {\n throw new ElementError({\n component: Tabs,\n identifier: `Links (\\`<a class=\"${tabClass}\">\\`)`\n })\n }\n\n this.$tabs = $tabs\n\n // Save bound functions so we can remove event listeners during teardown\n this.boundTabClick = this.onTabClick.bind(this)\n this.boundTabKeydown = this.onTabKeydown.bind(this)\n this.boundOnHashChange = this.onHashChange.bind(this)\n\n const $tabList = this.$root.querySelector(`ul.${listClass}`)\n const $tabListItems = this.$root.querySelectorAll(`li.${listItemClass}`)\n\n if (!$tabList) {\n throw new ElementError({\n component: Tabs,\n identifier: `List (\\`<ul class=\"${listClass}\">\\`)`\n })\n }\n\n if (!$tabListItems.length) {\n throw new ElementError({\n component: Tabs,\n identifier: `List items (\\`<li class=\"${listItemClass}\">\\`)`\n })\n }\n\n this.$tabList = $tabList\n this.$tabListItems = $tabListItems\n\n this.setupResponsiveChecks()\n }\n\n /**\n * Setup viewport resize check\n */\n setupResponsiveChecks() {\n const breakpoint = getBreakpoint('tablet')\n\n if (!breakpoint.value) {\n throw new ElementError({\n component: Tabs,\n identifier: `CSS custom property (\\`${breakpoint.property}\\`) on pseudo-class \\`:root\\``\n })\n }\n\n // Media query list for NHS.UK frontend tablet breakpoint\n this.mql = window.matchMedia(`(min-width: ${breakpoint.value})`)\n\n // MediaQueryList.addEventListener isn't supported by Safari < 14 so we need\n // to be able to fall back to the deprecated MediaQueryList.addListener\n if ('addEventListener' in this.mql) {\n this.mql.addEventListener('change', () => this.checkMode())\n } else {\n // @ts-expect-error Property 'addListener' does not exist\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n this.mql.addListener(() => this.checkMode())\n }\n\n this.checkMode()\n }\n\n /**\n * Setup or teardown handler for viewport resize check\n */\n checkMode() {\n if (this.mql?.matches) {\n this.setup()\n } else {\n this.teardown()\n }\n }\n\n /**\n * Setup tab component\n */\n setup() {\n this.$tabList.setAttribute('role', 'tablist')\n\n this.$tabListItems.forEach(($item) => {\n $item.setAttribute('role', 'presentation')\n })\n\n this.$tabs.forEach(($tab) => {\n // Set HTML attributes\n this.setAttributes($tab)\n\n // Handle events\n $tab.addEventListener('click', this.boundTabClick, true)\n $tab.addEventListener('keydown', this.boundTabKeydown, true)\n\n // Remove old active panels\n this.hideTab($tab)\n })\n\n // Show either the active tab according to the URL's hash or the first tab\n const $activeTab = this.getTab(window.location.hash) ?? this.$tabs[0]\n\n this.showTab($activeTab)\n\n // Handle hashchange events\n window.addEventListener('hashchange', this.boundOnHashChange, true)\n }\n\n /**\n * Teardown tab component\n */\n teardown() {\n this.$tabList.removeAttribute('role')\n\n this.$tabListItems.forEach(($item) => {\n $item.removeAttribute('role')\n })\n\n this.$tabs.forEach(($tab) => {\n // Remove events\n $tab.removeEventListener('click', this.boundTabClick, true)\n $tab.removeEventListener('keydown', this.boundTabKeydown, true)\n\n // Unset HTML attributes\n this.unsetAttributes($tab)\n })\n\n // Remove hashchange event handler\n window.removeEventListener('hashchange', this.boundOnHashChange, true)\n }\n\n /**\n * Handle hashchange event\n *\n * @returns {void} Returns void when prevented\n */\n onHashChange() {\n const { hash } = window.location\n const $tabWithHash = this.getTab(hash)\n if (!$tabWithHash) {\n return\n }\n\n // Prevent changing the hash\n if (this.changingHash) {\n this.changingHash = false\n return\n }\n\n // Show either the active tab according to the URL's hash or the first tab\n const $previousTab = this.getCurrentTab()\n if (!$previousTab) {\n return\n }\n\n this.hideTab($previousTab)\n this.showTab($tabWithHash)\n $tabWithHash.focus()\n }\n\n /**\n * Hide panel for tab link\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n hideTab($tab) {\n this.unhighlightTab($tab)\n this.hidePanel($tab)\n }\n\n /**\n * Show panel for tab link\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n showTab($tab) {\n this.highlightTab($tab)\n this.showPanel($tab)\n }\n\n /**\n * Get tab link by hash\n *\n * @param {string} hash - Hash fragment including #\n * @returns {HTMLAnchorElement | null} Tab link\n */\n getTab(hash) {\n const { tabClass } = this.config\n return this.$root.querySelector(`a.${tabClass}[href=\"${hash}\"]`)\n }\n\n /**\n * Set tab link and panel attributes\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n setAttributes($tab) {\n const panelId = $tab.hash.replace('#', '')\n if (!panelId) {\n return\n }\n\n // Set tab attributes\n $tab.setAttribute('id', `tab_${panelId}`)\n $tab.setAttribute('role', 'tab')\n $tab.setAttribute('aria-controls', panelId)\n $tab.setAttribute('aria-selected', 'false')\n $tab.setAttribute('tabindex', '-1')\n\n // Set panel attributes\n const $panel = this.getPanel($tab)\n if (!$panel) {\n return\n }\n\n const { panelClass } = this.config\n\n $panel.setAttribute('role', 'tabpanel')\n $panel.setAttribute('aria-labelledby', $tab.id)\n $panel.classList.add(this.jsHiddenClass ?? `${panelClass}--hidden`)\n }\n\n /**\n * Unset tab link and panel attributes\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n unsetAttributes($tab) {\n // unset tab attributes\n $tab.removeAttribute('id')\n $tab.removeAttribute('role')\n $tab.removeAttribute('aria-controls')\n $tab.removeAttribute('aria-selected')\n $tab.removeAttribute('tabindex')\n\n // unset panel attributes\n const $panel = this.getPanel($tab)\n if (!$panel) {\n return\n }\n\n const { panelClass } = this.config\n\n $panel.removeAttribute('role')\n $panel.removeAttribute('aria-labelledby')\n $panel.classList.remove(this.jsHiddenClass ?? `${panelClass}--hidden`)\n }\n\n /**\n * Handle tab link clicks\n *\n * @param {MouseEvent} event - Mouse click event\n * @returns {void} Returns void\n */\n onTabClick(event) {\n const $currentTab = this.getCurrentTab()\n const $nextTab = event.currentTarget\n\n if (!$currentTab || !($nextTab instanceof HTMLAnchorElement)) {\n return\n }\n\n event.preventDefault()\n\n this.hideTab($currentTab)\n this.showTab($nextTab)\n this.createHistoryEntry($nextTab)\n }\n\n /**\n * Update browser URL hash fragment for tab\n *\n * - Allows back/forward to navigate tabs\n * - Avoids page jump when hash changes\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n createHistoryEntry($tab) {\n const $panel = this.getPanel($tab)\n if (!$panel) {\n return\n }\n\n // Save and restore the id so the page doesn't jump when a user clicks a tab\n // (which changes the hash)\n const panelId = $panel.id\n $panel.id = ''\n this.changingHash = true\n window.location.hash = panelId\n $panel.id = panelId\n }\n\n /**\n * Handle tab keydown event\n *\n * - Press right arrow for next tab\n * - Press left arrow for previous tab\n *\n * @param {KeyboardEvent} event - Keydown event\n */\n onTabKeydown(event) {\n switch (event.key) {\n // 'Left' and 'Right' required for Edge 16 support.\n case 'ArrowLeft':\n case 'Left':\n this.activatePreviousTab()\n event.preventDefault()\n break\n case 'ArrowRight':\n case 'Right':\n this.activateNextTab()\n event.preventDefault()\n break\n }\n }\n\n /**\n * Activate next tab\n */\n activateNextTab() {\n const $currentTab = this.getCurrentTab()\n if (!$currentTab?.parentElement) {\n return\n }\n\n const $nextTabListItem = $currentTab.parentElement.nextElementSibling\n if (!$nextTabListItem) {\n return\n }\n\n const { tabClass } = this.config\n\n const $nextTab = $nextTabListItem.querySelector(`a.${tabClass}`)\n if (!$nextTab) {\n return\n }\n\n this.hideTab($currentTab)\n this.showTab($nextTab)\n $nextTab.focus()\n this.createHistoryEntry($nextTab)\n }\n\n /**\n * Activate previous tab\n */\n activatePreviousTab() {\n const $currentTab = this.getCurrentTab()\n if (!$currentTab?.parentElement) {\n return\n }\n\n const $previousTabListItem =\n $currentTab.parentElement.previousElementSibling\n if (!$previousTabListItem) {\n return\n }\n\n const { tabClass } = this.config\n\n const $previousTab = $previousTabListItem.querySelector(`a.${tabClass}`)\n if (!$previousTab) {\n return\n }\n\n this.hideTab($currentTab)\n this.showTab($previousTab)\n $previousTab.focus()\n this.createHistoryEntry($previousTab)\n }\n\n /**\n * Get tab panel for tab link\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n * @returns {Element | null} Tab panel\n */\n getPanel($tab) {\n const panelId = $tab.hash.replace('#', '')\n if (!panelId) {\n return null\n }\n\n return this.$root.querySelector(`#${panelId}`)\n }\n\n /**\n * Show tab panel for tab link\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n showPanel($tab) {\n const $panel = this.getPanel($tab)\n if (!$panel) {\n return\n }\n\n const { panelClass } = this.config\n\n $panel.classList.remove(this.jsHiddenClass ?? `${panelClass}--hidden`)\n }\n\n /**\n * Hide tab panel for tab link\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n hidePanel($tab) {\n const $panel = this.getPanel($tab)\n if (!$panel) {\n return\n }\n\n const { panelClass } = this.config\n\n $panel.classList.add(this.jsHiddenClass ?? `${panelClass}--hidden`)\n }\n\n /**\n * Unset 'selected' state for tab link\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n unhighlightTab($tab) {\n if (!$tab.parentElement) {\n return\n }\n\n const { listItemClass } = this.config\n\n $tab.setAttribute('aria-selected', 'false')\n $tab.parentElement.classList.remove(`${listItemClass}--selected`)\n $tab.setAttribute('tabindex', '-1')\n }\n\n /**\n * Set 'selected' state for tab link\n *\n * @param {HTMLAnchorElement} $tab - Tab link\n */\n highlightTab($tab) {\n if (!$tab.parentElement) {\n return\n }\n\n const { listItemClass } = this.config\n\n $tab.setAttribute('aria-selected', 'true')\n $tab.parentElement.classList.add(`${listItemClass}--selected`)\n $tab.setAttribute('tabindex', '0')\n }\n\n /**\n * Get current tab link\n *\n * @returns {HTMLAnchorElement | null} Tab link\n */\n getCurrentTab() {\n const { listItemClass, tabClass } = this.config\n return this.$root.querySelector(`.${listItemClass}--selected a.${tabClass}`)\n }\n\n /**\n * Name for the component used when initialising using data-module attributes\n */\n static moduleName = 'nhsuk-tabs'\n\n /**\n * Tabs default config\n *\n * @see {@link TabsConfig}\n * @constant\n * @type {TabsConfig}\n */\n static defaults = Object.freeze({\n panelClass: 'nhsuk-tabs__panel',\n listClass: 'nhsuk-tabs__list',\n listItemClass: 'nhsuk-tabs__list-item',\n tabClass: 'nhsuk-tabs__tab'\n })\n\n /**\n * Tabs config schema\n *\n * @constant\n * @satisfies {Schema<TabsConfig>}\n */\n static schema = Object.freeze({\n properties: {\n panelClass: { type: 'string' },\n listClass: { type: 'string' },\n listItemClass: { type: 'string' },\n tabClass: { type: 'string' }\n }\n })\n}\n\n/**\n * Initialise tabs component\n *\n * @deprecated Use {@link createAll | `createAll(Tabs, options)`} instead.\n * @param {InitOptions & Partial<TabsConfig>} [options]\n */\nexport function initTabs(options) {\n const { scope: $scope } = normaliseOptions(options)\n\n const $tabs = $scope?.querySelectorAll(`[data-module=\"${Tabs.moduleName}\"]`)\n\n $tabs?.forEach(($root) => {\n new Tabs($root, options)\n })\n}\n\n/**\n * Tabs config\n *\n * @typedef {object} TabsConfig\n * @property {string} panelClass - Tabs panel class\n * @property {string} listClass - Tabs list class\n * @property {string} listItemClass - Tabs list item class\n * @property {string} tabClass - Tabs link class\n */\n\n/**\n * @import { createAll, InitOptions } from '../../index.mjs'\n * @import { Schema } from '../../common/configuration/index.mjs'\n */\n","import { normaliseOptions } from './common/configuration/index.mjs'\nimport { isObject, isSupported } from './common/index.mjs'\nimport {\n Button,\n CharacterCount,\n Checkboxes,\n ErrorSummary,\n FileUpload,\n Header,\n NotificationBanner,\n PasswordInput,\n Radios,\n SkipLink,\n Tabs\n} from './components/index.mjs'\nimport { ElementError, SupportError } from './errors/index.mjs'\n\n/**\n * Initialise all components\n *\n * Use the `data-module` attributes to find and initialise all of the\n * components provided as part of NHS.UK frontend.\n *\n * @overload\n * @param {Config} [config] - Config for all components (with optional scope)\n * @returns {void}\n */\n\n/**\n * @overload\n * @param {Element | Document | null} [$scope] - Scope of the document to search within\n * @returns {void}\n */\n\n/**\n * @param {Config | Element | Document | null} [scopeOrConfig]\n */\nexport function initAll(scopeOrConfig = {}) {\n const config = isObject(scopeOrConfig) ? scopeOrConfig : {}\n\n // Extract initialisation options\n const options = normaliseOptions(scopeOrConfig)\n\n try {\n // Skip initialisation when NHS.UK frontend is not supported\n if (!isSupported()) {\n throw new SupportError()\n }\n\n // Users can initialise NHS.UK frontend in certain sections of the page\n // unless the scope is null (for example, query selector not found)\n if (options.scope === null) {\n throw new ElementError({\n element: options.scope,\n identifier: 'NHS.UK frontend scope element (`$scope`)'\n })\n }\n } catch (error) {\n if (options.onError) {\n options.onError(error, {\n config\n })\n } else {\n console.log(error)\n }\n\n return\n }\n\n const components = /** @type {const} */ ([\n [Button, config.button],\n [CharacterCount, config.characterCount],\n [Checkboxes, config.checkboxes],\n [ErrorSummary, config.errorSummary],\n [FileUpload, config.fileUpload],\n [Header, config.header],\n [NotificationBanner, config.notificationBanner],\n [PasswordInput, config.passwordInput],\n [Radios, config.radios],\n [SkipLink, config.skipLink],\n [Tabs, config.tabs]\n ])\n\n components.forEach(([Component, componentConfig]) => {\n createAll(Component, componentConfig, options)\n })\n}\n\n/**\n * Create all instances of a specific component on the page\n *\n * Uses the `data-module` attribute to find all elements matching the specified\n * component on the page, creating instances of the component object for each\n * of them.\n *\n * Any component errors will be caught and logged to the console.\n *\n * @template {CompatibleClass | CompatibleClass<typeof ConfigurableComponent>} ComponentClass\n * @overload\n * @param {ComponentClass} Component - Component class to initialise\n * @param {ComponentConfig<ComponentClass>} [config] - Config supplied to component\n * @param {CreateAllOptions<ComponentClass>} [options] - Options including scope of the document to search within and callback function if error throw by component on init\n * @returns {InstanceType<ComponentClass>[]} Array of initialised components\n */\n\n/**\n * @template {CompatibleClass | CompatibleClass<typeof ConfigurableComponent>} ComponentClass\n * @overload\n * @param {ComponentClass} Component - Component class to initialise\n * @param {ComponentConfig<ComponentClass>} [config] - Config supplied to component\n * @param {OnErrorCallback<ComponentClass>} [onError] - Initialisation error callback\n * @returns {InstanceType<ComponentClass>[]} Array of initialised components\n */\n\n/**\n * @template {CompatibleClass | CompatibleClass<typeof ConfigurableComponent>} ComponentClass\n * @overload\n * @param {ComponentClass} Component - Component class to initialise\n * @param {ComponentConfig<ComponentClass>} [config] - Config supplied to component\n * @param {Element | Document | null} [$scope] - Scope of the document to search within\n * @returns {InstanceType<ComponentClass>[]} Array of initialised components\n */\n\n/**\n * @template {CompatibleClass | CompatibleClass<typeof ConfigurableComponent>} ComponentClass\n * @param {ComponentClass} Component - Component class to initialise\n * @param {ComponentConfig<ComponentClass>} [config] - Config supplied to component\n * @param {CreateAllOptions<ComponentClass> | OnErrorCallback<ComponentClass> | Element | Document | null} [scopeOrOptions]\n */\nexport function createAll(Component, config, scopeOrOptions) {\n let /** @type {NodeListOf<Element> | undefined} */ $elements\n\n // Extract initialisation options\n const options = normaliseOptions(scopeOrOptions)\n\n try {\n // Skip initialisation when NHS.UK frontend is not supported\n if (!isSupported()) {\n throw new SupportError()\n }\n\n // Users can initialise NHS.UK frontend in certain sections of the page\n // unless the scope is null (for example, query selector not found)\n if (options.scope === null) {\n throw new ElementError({\n element: options.scope,\n component: Component,\n identifier: 'Scope element (`$scope`)'\n })\n }\n\n $elements = options.scope?.querySelectorAll(\n `[data-module=\"${Component.moduleName}\"]`\n )\n } catch (error) {\n if (options.onError) {\n options.onError(error, {\n component: Component,\n config\n })\n } else {\n console.log(error)\n }\n\n return []\n }\n\n return Array.from($elements ?? [])\n .map(($element) => {\n try {\n return /** @type {InstanceType<ComponentClass>} */ (\n // Only pass config to components that accept it\n !!config && 'defaults' in Component\n ? new Component($element, config)\n : new Component($element)\n )\n } catch (error) {\n if (options.onError) {\n options.onError(error, {\n element: $element,\n component: Component,\n config\n })\n } else {\n console.log(error)\n }\n\n return null\n }\n })\n .filter((instance) => !!instance) // Exclude components that errored\n}\n\nexport * from './i18n.mjs'\nexport * from './common/index.mjs'\nexport * from './components/index.mjs'\nexport * from './errors/index.mjs'\n\n/**\n * NHS.UK frontend config for all components via `initAll()`\n *\n * @typedef {object} Config\n * @property {Element | Document | null} [scope] - Scope of the document to search within\n * @property {OnErrorCallback<CompatibleClass>} [onError] - Initialisation error callback\n * @property {ComponentConfig<typeof Button>} [button] - Button config\n * @property {ComponentConfig<typeof CharacterCount>} [characterCount] - Character count config\n * @property {ComponentConfig<typeof Checkboxes>} [checkboxes] - Checkboxes config\n * @property {ComponentConfig<typeof ErrorSummary>} [errorSummary] - Error Summary config\n * @property {ComponentConfig<typeof FileUpload>} [fileUpload] - File upload config\n * @property {ComponentConfig<typeof Header>} [header] - Header config\n * @property {ComponentConfig<typeof NotificationBanner>} [notificationBanner] - Notification Banner config\n * @property {ComponentConfig<typeof PasswordInput>} [passwordInput] - Password Input config\n * @property {ComponentConfig<typeof Radios>} [radios] - Radios config\n * @property {ComponentConfig<typeof SkipLink>} [skipLink] - Skip Link config\n * @property {ComponentConfig<typeof Tabs>} [tabs] - Tabs config\n */\n\n/**\n * Component config keys, e.g. `button` and `characterCount`\n *\n * @typedef {keyof Omit<Config, 'scope' | 'onError'>} ConfigKey\n */\n\n/**\n * Component config\n *\n * @template {CompatibleClass} ComponentClass\n * @typedef {ConstructorParameters<ComponentClass>[1]} ComponentConfig\n */\n\n/**\n * Initialisation error context\n *\n * Contains the element, component class and configuration\n *\n * @template {CompatibleClass} ComponentClass\n * @typedef {object} ErrorContext\n * @property {Element} [element] - Element used for component module initialisation\n * @property {ComponentClass} [component] - Class of component\n * @property {Config | ComponentConfig<ComponentClass>} config - Config supplied to components\n */\n\n/**\n * Initialisation error callback\n *\n * @template {CompatibleClass} ComponentClass\n * @callback OnErrorCallback\n * @param {unknown} error - Thrown error\n * @param {ErrorContext<ComponentClass>} context - Object containing the element, component class and configuration\n */\n\n/**\n * Initialisation options\n *\n * @template {CompatibleClass} ComponentClass\n * @typedef {object} CreateAllOptions\n * @property {Element | Document | null} [scope] - Scope of the document to search within\n * @property {OnErrorCallback<ComponentClass>} [onError] - Initialisation error callback\n */\n\n/**\n * @import { CompatibleClass } from './component.mjs'\n * @import { ConfigurableComponent } from './configurable-component.mjs'\n */\n"],"names":["closestAttributeValue","$element","attributeName","$closestElementWithAttribute","closest","getAttribute","version","toggleConditionalInput","$input","className","HTMLInputElement","targetId","target","document","getElementById","setAttribute","checked","toString","classList","toggle","getBreakpoint","name","property","value","window","getComputedStyle","documentElement","getPropertyValue","undefined","setFocus","options","isFocusable","onBlur","removeEventListener","call","removeAttribute","addEventListener","onFocus","onBeforeFocus","focus","isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","body","contains","isObject","option","Array","isArray","isScope","Element","Document","formatErrorMessage","Component","message","normaliseString","isValid","trimmedValue","trim","output","outputType","type","includes","length","isFinite","Number","normaliseArray","values","_JSON$parse","JSON","parse","decodeURIComponent","getArrayValue","_unused","map","filter","key","extractConfigByNamespace","schema","dataset","namespace","properties","newObject","Object","entries","current","keyParts","split","index","mergeConfigs","configObjects","formattedConfigObject","configObject","keys","override","NHSUKFrontendError","Error","constructor","args","super","this","SupportError","supportMessage","HTMLScriptElement","prototype","ConfigError","ElementError","component","identifier","element","expectedType","InitError","componentOrMessage","normaliseOptions","scopeOrOptions","onError","scope","_self","globalThis","self","childConstructor","elementType","checkSupport","checkInitialised","ConfigurableComponent","config","defaults","datasetConfig","out","entry","field","normaliseDataset","configOverride","_datasetConfig","Button","debounceFormSubmitTimer","event","handleKeyDown","debounce","preventDefault","click","preventDoubleClick","setTimeout","DEBOUNCE_TIMEOUT_IN_SECONDS","initButtons","$buttons","querySelectorAll","forEach","freeze","I18n","translations","_config$locale","locale","lang","t","lookupKey","translation","count","translationPluralForm","getPluralSuffix","match","replacePlaceholders","translationString","formatter","Intl","NumberFormat","supportedLocalesOf","replace","placeholderWithBraces","placeholderKey","hasOwnProperty","placeholderValue","format","hasIntlPluralRulesSupport","Boolean","PluralRules","preferredForm","select","console","warn","CharacterCount","_ref","lastInputTimestamp","lastInputValue","valueChecker","$textarea","querySelector","HTMLTextAreaElement","errors","validationErrors","conditions","required","errorMessage","every","push","validateConfig","i18n","maxwords","maxlength","screenReaderCountMessageClass","textareaDescriptionClass","visibleCountMessageClass","maxLength","Infinity","textareaDescriptionId","id","$textareaDescription","$errorMessage","exec","textContent","insertAdjacentElement","$screenReaderCountMessage","createElement","add","$visibleCountMessage","remove","bindChangeEvents","updateCountMessage","configOverrides","text","_text$match","handleKeyUp","handleFocus","handleBlur","checkIfValueChanged","updateVisibleCountMessage","updateScreenReaderCountMessage","isError","isOverThreshold","formattedUpdateMessage","remainingNumber","countType","formatCountMessage","translationKeySuffix","Math","abs","threshold","currentLength","Date","now","setInterval","clearInterval","initCharacterCounts","$characterCounts","charactersUnderLimit","one","other","charactersAtLimit","charactersOverLimit","wordsUnderLimit","wordsAtLimit","wordsOverLimit","textareaDescription","anyOf","Checkboxes","$inputs","_$input$dataset$ariaC","ariaControls","syncAllConditionalReveals","handleClick","syncConditionalRevealWithInputState","conditionalClass","unCheckAllInputsExcept","checkboxExclusiveGroup","exclusiveGroup","selectorGroup","$inputWithSameName","form","setInputState","unCheckExclusiveInputs","$exclusiveInput","$clickedInput","initCheckboxes","$checkboxes","ErrorSummary","disableAutoFocus","focusOnPageLoad","getAssociatedLegendOrLabel","_document$querySelect","$fieldset","$legends","getElementsByTagName","$candidateLegend","legendTop","getBoundingClientRect","top","inputRect","height","innerHeight","focusTarget","$target","HTMLAnchorElement","inputId","hash","$legendOrLabel","scrollIntoView","preventScroll","initErrorSummary","FileUpload","enteredAnotherElement","dropZoneClass","dropButtonClass","dropButtonGroupClass","dropInstructionClass","chooseFilesButtonClass","chooseFilesButtonClassList","announcementsClass","statusClass","$label","findLabel","$dropZone","$dropButton","ariaDescribedBy","$status","innerText","formatStatusMessage","appendChild","$statusComma","$dropButtonGroup","$chooseFilesButton","append","$dropInstruction","_this$$input$parentEl","onClick","bind","parentElement","insertBefore","onChange","updateDisabledState","observeDisabledState","$announcements","onDrop","updateDropzoneVisibility","disabled","hideDraggingState","Node","dataTransfer","canDrop","showDraggingState","canFillInput","files","dispatchEvent","CustomEvent","matchesInputCapacity","items","list","result","i","kind","countFileItems","types","numberOfFiles","multiple","fileCount","MutationObserver","mutationList","mutation","observe","attributes","disabledStateClass","initFileUploads","$fileUploads","chooseFilesButton","dropInstruction","noFileChosen","multipleFilesChosen","enteredDropZone","leftDropZone","Header","$navigation","$navigationList","$navigationItems","$menu","$menuToggle","$menuList","width","breakpoints","updateNavigationTimer","menuIsEnabled","menuIsOpen","navigationClass","navigationListClass","navigationItemClass","menuClass","menuToggleClass","HTMLButtonElement","handleEscapeKey","onEscapeKey","handleUpdateNavigation","updateNavigation","handleToggleMenu","toggleMenu","setupNavigation","resetNavigation","right","breakpoint","offsetWidth","clearTimeout","setupMenu","menuListClass","enableMenu","disableMenu","closeMenu","style","removeProperty","openMenu","setProperty","offsetHeight","initHeader","NotificationBanner","initNotificationBanners","$notificationBanners","$notificationBanner","PasswordInput","$showHideButton","screenReaderStatusMessageClass","$screenReaderStatusMessage","hide","persisted","show","setType","isHidden","prefixButton","prefixStatus","initPasswordInputs","$passwordInputs","showPassword","hidePassword","showPasswordAriaLabel","hidePasswordAriaLabel","passwordShownAnnouncement","passwordHiddenAnnouncement","Radios","$allInputs","$clickedInputForm","$clickedInputName","hasSameFormOwner","initRadios","$radios","SkipLink","_this$$root$getAttrib","href","origin","location","pathname","linkedElementId","$linkedElement","focusedElementClassList","initSkipLinks","$skipLinks","Tabs","changingHash","jsHiddenClass","mql","listClass","listItemClass","tabClass","$tabs","boundTabClick","onTabClick","boundTabKeydown","onTabKeydown","boundOnHashChange","onHashChange","$tabList","$tabListItems","setupResponsiveChecks","matchMedia","checkMode","addListener","_this$mql","matches","setup","teardown","_this$getTab","$item","$tab","setAttributes","hideTab","$activeTab","getTab","showTab","unsetAttributes","$tabWithHash","$previousTab","getCurrentTab","unhighlightTab","hidePanel","highlightTab","showPanel","_this$jsHiddenClass","panelId","$panel","getPanel","panelClass","_this$jsHiddenClass2","$currentTab","$nextTab","currentTarget","createHistoryEntry","activatePreviousTab","activateNextTab","$nextTabListItem","nextElementSibling","$previousTabListItem","previousElementSibling","_this$jsHiddenClass3","_this$jsHiddenClass4","initTabs","initAll","scopeOrConfig","error","log","button","characterCount","checkboxes","errorSummary","fileUpload","header","notificationBanner","passwordInput","radios","skipLink","tabs","componentConfig","createAll","$elements","_options$scope","from","instance"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index.js');
4
+
5
+ // Initialise components
6
+ document.addEventListener('DOMContentLoaded', () => index.initAll(document));
7
+ //# sourceMappingURL=nhsuk.js.map