@ministryofjustice/frontend 4.0.1 → 5.1.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 (256) hide show
  1. package/govuk-prototype-kit.config.json +19 -4
  2. package/moj/_base.scss +2 -0
  3. package/moj/_base.scss.map +1 -0
  4. package/moj/all.bundle.js +3010 -0
  5. package/moj/all.bundle.js.map +1 -0
  6. package/moj/all.bundle.mjs +3293 -0
  7. package/moj/all.bundle.mjs.map +1 -0
  8. package/moj/all.mjs +17 -110
  9. package/moj/all.mjs.map +1 -1
  10. package/moj/all.scss +3 -0
  11. package/moj/all.scss.map +1 -0
  12. package/moj/common/index.mjs +57 -0
  13. package/moj/common/index.mjs.map +1 -0
  14. package/moj/common/moj-frontend-version.mjs +14 -0
  15. package/moj/common/moj-frontend-version.mjs.map +1 -0
  16. package/moj/components/_all.scss +2 -0
  17. package/moj/components/_all.scss.map +1 -0
  18. package/moj/components/action-bar/_action-bar.scss +2 -0
  19. package/moj/components/action-bar/_action-bar.scss.map +1 -0
  20. package/moj/components/add-another/_add-another.scss +2 -0
  21. package/moj/components/add-another/_add-another.scss.map +1 -0
  22. package/moj/components/add-another/add-another.bundle.js +157 -0
  23. package/moj/components/add-another/add-another.bundle.js.map +1 -0
  24. package/moj/components/add-another/add-another.bundle.mjs +271 -0
  25. package/moj/components/add-another/add-another.bundle.mjs.map +1 -0
  26. package/moj/components/add-another/add-another.mjs +135 -91
  27. package/moj/components/add-another/add-another.mjs.map +1 -1
  28. package/moj/components/alert/_alert.scss +4 -0
  29. package/moj/components/alert/_alert.scss.map +1 -0
  30. package/moj/components/alert/alert.bundle.js +254 -0
  31. package/moj/components/alert/alert.bundle.js.map +1 -0
  32. package/moj/components/alert/alert.bundle.mjs +490 -0
  33. package/moj/components/alert/alert.bundle.mjs.map +1 -0
  34. package/moj/components/alert/alert.mjs +97 -218
  35. package/moj/components/alert/alert.mjs.map +1 -1
  36. package/moj/components/alert/{alert.spec.helper.js → alert.spec.helper.bundle.js} +1 -1
  37. package/moj/components/alert/alert.spec.helper.bundle.js.map +1 -0
  38. package/moj/components/alert/alert.spec.helper.bundle.mjs +67 -0
  39. package/moj/components/alert/alert.spec.helper.bundle.mjs.map +1 -0
  40. package/moj/components/alert/alert.spec.helper.mjs.map +1 -1
  41. package/moj/components/badge/_badge.scss +2 -0
  42. package/moj/components/badge/_badge.scss.map +1 -0
  43. package/moj/components/banner/_banner.scss +2 -0
  44. package/moj/components/banner/_banner.scss.map +1 -0
  45. package/moj/components/button-menu/README.md +12 -6
  46. package/moj/components/button-menu/_button-menu.scss +4 -1
  47. package/moj/components/button-menu/_button-menu.scss.map +1 -0
  48. package/moj/components/button-menu/button-menu.bundle.js +270 -0
  49. package/moj/components/button-menu/button-menu.bundle.js.map +1 -0
  50. package/moj/components/button-menu/button-menu.bundle.mjs +506 -0
  51. package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -0
  52. package/moj/components/button-menu/button-menu.mjs +214 -280
  53. package/moj/components/button-menu/button-menu.mjs.map +1 -1
  54. package/moj/components/cookie-banner/_cookie-banner.scss +2 -0
  55. package/moj/components/cookie-banner/_cookie-banner.scss.map +1 -0
  56. package/moj/components/currency-input/_currency-input.scss +2 -0
  57. package/moj/components/currency-input/_currency-input.scss.map +1 -0
  58. package/moj/components/date-picker/_date-picker.scss +2 -0
  59. package/moj/components/date-picker/_date-picker.scss.map +1 -0
  60. package/moj/components/date-picker/date-picker.bundle.js +804 -0
  61. package/moj/components/date-picker/date-picker.bundle.js.map +1 -0
  62. package/moj/components/date-picker/date-picker.bundle.mjs +1040 -0
  63. package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -0
  64. package/moj/components/date-picker/date-picker.mjs +663 -827
  65. package/moj/components/date-picker/date-picker.mjs.map +1 -1
  66. package/moj/components/filter/_filter.scss +2 -0
  67. package/moj/components/filter/_filter.scss.map +1 -0
  68. package/moj/components/filter/template.njk +1 -1
  69. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +185 -0
  70. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -0
  71. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +421 -0
  72. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -0
  73. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +166 -81
  74. package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
  75. package/moj/components/form-validator/form-validator.bundle.js +288 -0
  76. package/moj/components/form-validator/form-validator.bundle.js.map +1 -0
  77. package/moj/components/form-validator/form-validator.bundle.mjs +524 -0
  78. package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -0
  79. package/moj/components/form-validator/form-validator.mjs +226 -149
  80. package/moj/components/form-validator/form-validator.mjs.map +1 -1
  81. package/moj/components/header/_header.scss +2 -0
  82. package/moj/components/header/_header.scss.map +1 -0
  83. package/moj/components/identity-bar/_identity-bar.scss +2 -0
  84. package/moj/components/identity-bar/_identity-bar.scss.map +1 -0
  85. package/moj/components/interruption-card/_interruption-card.scss +2 -0
  86. package/moj/components/interruption-card/_interruption-card.scss.map +1 -0
  87. package/moj/components/messages/_messages.scss +2 -0
  88. package/moj/components/messages/_messages.scss.map +1 -0
  89. package/moj/components/multi-file-upload/_multi-file-upload.scss +2 -0
  90. package/moj/components/multi-file-upload/_multi-file-upload.scss.map +1 -0
  91. package/moj/components/multi-file-upload/multi-file-upload.bundle.js +397 -0
  92. package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -0
  93. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +633 -0
  94. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -0
  95. package/moj/components/multi-file-upload/multi-file-upload.mjs +384 -213
  96. package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
  97. package/moj/components/multi-file-upload/template.njk +1 -1
  98. package/moj/components/multi-select/_multi-select.scss +2 -0
  99. package/moj/components/multi-select/_multi-select.scss.map +1 -0
  100. package/moj/components/multi-select/multi-select.bundle.js +143 -0
  101. package/moj/components/multi-select/multi-select.bundle.js.map +1 -0
  102. package/moj/components/multi-select/multi-select.bundle.mjs +379 -0
  103. package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -0
  104. package/moj/components/multi-select/multi-select.mjs +123 -64
  105. package/moj/components/multi-select/multi-select.mjs.map +1 -1
  106. package/moj/components/notification-badge/_notification-badge.scss +2 -0
  107. package/moj/components/notification-badge/_notification-badge.scss.map +1 -0
  108. package/moj/components/organisation-switcher/_organisation-switcher.scss +2 -0
  109. package/moj/components/organisation-switcher/_organisation-switcher.scss.map +1 -0
  110. package/moj/components/page-header-actions/_page-header-actions.scss +2 -0
  111. package/moj/components/page-header-actions/_page-header-actions.scss.map +1 -0
  112. package/moj/components/pagination/_pagination.scss +2 -2
  113. package/moj/components/pagination/_pagination.scss.map +1 -0
  114. package/moj/components/password-reveal/_password-reveal.scss +5 -1
  115. package/moj/components/password-reveal/_password-reveal.scss.map +1 -0
  116. package/moj/components/password-reveal/password-reveal.bundle.js +52 -0
  117. package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -0
  118. package/moj/components/password-reveal/password-reveal.bundle.mjs +166 -0
  119. package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -0
  120. package/moj/components/password-reveal/password-reveal.mjs +39 -29
  121. package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
  122. package/moj/components/primary-navigation/_primary-navigation.scss +2 -0
  123. package/moj/components/primary-navigation/_primary-navigation.scss.map +1 -0
  124. package/moj/components/progress-bar/_progress-bar.scss +2 -0
  125. package/moj/components/progress-bar/_progress-bar.scss.map +1 -0
  126. package/moj/components/rich-text-editor/README.md +16 -9
  127. package/moj/components/rich-text-editor/_rich-text-editor.scss +2 -0
  128. package/moj/components/rich-text-editor/_rich-text-editor.scss.map +1 -0
  129. package/moj/components/rich-text-editor/rich-text-editor.bundle.js +210 -0
  130. package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -0
  131. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +446 -0
  132. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -0
  133. package/moj/components/rich-text-editor/rich-text-editor.mjs +186 -140
  134. package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
  135. package/moj/components/search/_search.scss +2 -0
  136. package/moj/components/search/_search.scss.map +1 -0
  137. package/moj/components/search-toggle/{search-toggle.scss → _search-toggle.scss} +2 -0
  138. package/moj/components/search-toggle/_search-toggle.scss.map +1 -0
  139. package/moj/components/search-toggle/search-toggle.bundle.js +122 -0
  140. package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -0
  141. package/moj/components/search-toggle/search-toggle.bundle.mjs +358 -0
  142. package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -0
  143. package/moj/components/search-toggle/search-toggle.mjs +104 -43
  144. package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
  145. package/moj/components/side-navigation/_side-navigation.scss +2 -0
  146. package/moj/components/side-navigation/_side-navigation.scss.map +1 -0
  147. package/moj/components/sortable-table/_sortable-table.scss +2 -2
  148. package/moj/components/sortable-table/_sortable-table.scss.map +1 -0
  149. package/moj/components/sortable-table/sortable-table.bundle.js +202 -0
  150. package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -0
  151. package/moj/components/sortable-table/sortable-table.bundle.mjs +438 -0
  152. package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -0
  153. package/moj/components/sortable-table/sortable-table.mjs +179 -122
  154. package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
  155. package/moj/components/sub-navigation/_sub-navigation.scss +2 -0
  156. package/moj/components/sub-navigation/_sub-navigation.scss.map +1 -0
  157. package/moj/components/tag/_tag.scss +2 -0
  158. package/moj/components/tag/_tag.scss.map +1 -0
  159. package/moj/components/task-list/_task-list.scss +2 -0
  160. package/moj/components/task-list/_task-list.scss.map +1 -0
  161. package/moj/components/ticket-panel/_ticket-panel.scss +2 -0
  162. package/moj/components/ticket-panel/_ticket-panel.scss.map +1 -0
  163. package/moj/components/timeline/_timeline.scss +2 -0
  164. package/moj/components/timeline/_timeline.scss.map +1 -0
  165. package/moj/core/_all.scss +3 -0
  166. package/moj/core/_all.scss.map +1 -0
  167. package/moj/core/_moj-frontend-properties.scss +7 -0
  168. package/moj/core/_moj-frontend-properties.scss.map +1 -0
  169. package/moj/filters/all.js +44 -22
  170. package/moj/filters/prototype-kit-13-filters.js +4 -3
  171. package/moj/helpers/_all.scss +2 -0
  172. package/moj/helpers/_all.scss.map +1 -0
  173. package/moj/helpers/_hidden.scss +2 -0
  174. package/moj/helpers/_hidden.scss.map +1 -0
  175. package/moj/helpers/_links.scss +2 -0
  176. package/moj/helpers/_links.scss.map +1 -0
  177. package/moj/helpers.bundle.js +140 -0
  178. package/moj/helpers.bundle.js.map +1 -0
  179. package/moj/helpers.bundle.mjs +128 -0
  180. package/moj/helpers.bundle.mjs.map +1 -0
  181. package/moj/helpers.mjs +50 -77
  182. package/moj/helpers.mjs.map +1 -1
  183. package/moj/init.js +11 -2
  184. package/moj/moj-frontend.min.css +1 -1
  185. package/moj/moj-frontend.min.css.map +1 -1
  186. package/moj/moj-frontend.min.js +1 -1
  187. package/moj/moj-frontend.min.js.map +1 -1
  188. package/moj/objects/_all.scss +2 -0
  189. package/moj/objects/_all.scss.map +1 -0
  190. package/moj/objects/_button-group.scss +2 -0
  191. package/moj/objects/_button-group.scss.map +1 -0
  192. package/moj/objects/_filter-layout.scss +2 -0
  193. package/moj/objects/_filter-layout.scss.map +1 -0
  194. package/moj/objects/_scrollable-pane.scss +2 -0
  195. package/moj/objects/_scrollable-pane.scss.map +1 -0
  196. package/moj/objects/_width-container.scss +2 -0
  197. package/moj/objects/_width-container.scss.map +1 -0
  198. package/moj/settings/_all.scss +2 -0
  199. package/moj/settings/_all.scss.map +1 -0
  200. package/moj/settings/_assets.scss +2 -0
  201. package/moj/settings/_assets.scss.map +1 -0
  202. package/moj/settings/_colours.scss +2 -0
  203. package/moj/settings/_colours.scss.map +1 -0
  204. package/moj/settings/_measurements.scss +2 -0
  205. package/moj/settings/_measurements.scss.map +1 -0
  206. package/moj/settings/_typography.scss +2 -0
  207. package/moj/settings/_typography.scss.map +1 -0
  208. package/moj/template.njk +13 -0
  209. package/moj/utilities/_all.scss +2 -0
  210. package/moj/utilities/_all.scss.map +1 -0
  211. package/moj/utilities/_hidden.scss +2 -0
  212. package/moj/utilities/_hidden.scss.map +1 -0
  213. package/moj/utilities/_width-container.scss +2 -0
  214. package/moj/utilities/_width-container.scss.map +1 -0
  215. package/moj/vendor/govuk-frontend/_base.scss +2 -0
  216. package/moj/vendor/govuk-frontend/_base.scss.map +1 -0
  217. package/moj/vendor/govuk-frontend/_index.scss +2 -0
  218. package/moj/vendor/govuk-frontend/_index.scss.map +1 -0
  219. package/package.json +5 -6
  220. package/moj/all.jquery.min.js +0 -1
  221. package/moj/all.jquery.min.js.map +0 -1
  222. package/moj/all.js +0 -2662
  223. package/moj/all.js.map +0 -1
  224. package/moj/components/add-another/add-another.js +0 -115
  225. package/moj/components/add-another/add-another.js.map +0 -1
  226. package/moj/components/alert/alert.js +0 -356
  227. package/moj/components/alert/alert.js.map +0 -1
  228. package/moj/components/alert/alert.spec.helper.js.map +0 -1
  229. package/moj/components/button-menu/button-menu.js +0 -338
  230. package/moj/components/button-menu/button-menu.js.map +0 -1
  231. package/moj/components/date-picker/date-picker.js +0 -970
  232. package/moj/components/date-picker/date-picker.js.map +0 -1
  233. package/moj/components/filter-toggle-button/filter-toggle-button.js +0 -102
  234. package/moj/components/filter-toggle-button/filter-toggle-button.js.map +0 -1
  235. package/moj/components/form-validator/form-validator.js +0 -205
  236. package/moj/components/form-validator/form-validator.js.map +0 -1
  237. package/moj/components/multi-file-upload/multi-file-upload.js +0 -241
  238. package/moj/components/multi-file-upload/multi-file-upload.js.map +0 -1
  239. package/moj/components/multi-select/multi-select.js +0 -86
  240. package/moj/components/multi-select/multi-select.js.map +0 -1
  241. package/moj/components/password-reveal/password-reveal.js +0 -44
  242. package/moj/components/password-reveal/password-reveal.js.map +0 -1
  243. package/moj/components/rich-text-editor/rich-text-editor.js +0 -166
  244. package/moj/components/rich-text-editor/rich-text-editor.js.map +0 -1
  245. package/moj/components/search-toggle/search-toggle.js +0 -63
  246. package/moj/components/search-toggle/search-toggle.js.map +0 -1
  247. package/moj/components/sortable-table/sortable-table.js +0 -147
  248. package/moj/components/sortable-table/sortable-table.js.map +0 -1
  249. package/moj/helpers.js +0 -200
  250. package/moj/helpers.js.map +0 -1
  251. package/moj/vendor/html5shiv.js +0 -326
  252. package/moj/vendor/jquery.js +0 -9300
  253. package/moj/version.js +0 -12
  254. package/moj/version.js.map +0 -1
  255. package/moj/version.mjs +0 -4
  256. package/moj/version.mjs.map +0 -1
@@ -1,15 +1,210 @@
1
+ import { ConfigurableComponent } from 'govuk-frontend';
1
2
  import { addAttributeValue, removeAttributeValue } from '../../helpers.mjs';
2
3
 
3
- function FormValidator(form, options) {
4
- this.form = form;
5
- this.errors = [];
6
- this.validators = [];
7
- $(this.form).on('submit', $.proxy(this, 'onSubmit'));
8
- this.summary =
9
- options && options.summary ? $(options.summary) : $('.govuk-error-summary');
10
- this.originalTitle = document.title;
4
+ /**
5
+ * @augments {ConfigurableComponent<FormValidatorConfig, HTMLFormElement>}
6
+ */
7
+ class FormValidator extends ConfigurableComponent {
8
+ /**
9
+ * @param {Element | null} $root - HTML element to use for form validator
10
+ * @param {FormValidatorConfig} [config] - Form validator config
11
+ */
12
+ constructor($root, config = {}) {
13
+ super($root, config);
14
+ const $summary = this.config.summary.element || document.querySelector(this.config.summary.selector);
15
+ if (!$summary || !($summary instanceof HTMLElement)) {
16
+ return this;
17
+ }
18
+ this.$summary = $summary;
19
+ this.errors = /** @type {ValidationError[]} */[];
20
+ this.validators = /** @type {Validator[]} */[];
21
+ this.originalTitle = document.title;
22
+ this.$root.addEventListener('submit', this.onSubmit.bind(this));
23
+ }
24
+ escapeHtml(string = '') {
25
+ return String(string).replace(/[&<>"'`=/]/g, name => FormValidator.entityMap[name]);
26
+ }
27
+ resetTitle() {
28
+ document.title = this.originalTitle;
29
+ }
30
+ updateTitle() {
31
+ document.title = `${this.errors.length} errors - ${document.title}`;
32
+ }
33
+ showSummary() {
34
+ this.$summary.innerHTML = this.getSummaryHtml();
35
+ this.$summary.classList.remove('moj-hidden');
36
+ this.$summary.setAttribute('aria-labelledby', 'errorSummary-heading');
37
+ this.$summary.focus();
38
+ }
39
+ getSummaryHtml() {
40
+ let html = '<h2 id="error-summary-title" class="govuk-error-summary__title">There is a problem</h2>';
41
+ html += '<div class="govuk-error-summary__body">';
42
+ html += '<ul class="govuk-list govuk-error-summary__list">';
43
+ for (const error of this.errors) {
44
+ html += '<li>';
45
+ html += `<a href="#${this.escapeHtml(error.fieldName)}">`;
46
+ html += this.escapeHtml(error.message);
47
+ html += '</a>';
48
+ html += '</li>';
49
+ }
50
+ html += '</ul>';
51
+ html += '</div>';
52
+ return html;
53
+ }
54
+ hideSummary() {
55
+ this.$summary.classList.add('moj-hidden');
56
+ this.$summary.removeAttribute('aria-labelledby');
57
+ }
58
+
59
+ /**
60
+ * @param {SubmitEvent} event - Form submit event
61
+ */
62
+ onSubmit(event) {
63
+ this.removeInlineErrors();
64
+ this.hideSummary();
65
+ this.resetTitle();
66
+ if (!this.validate()) {
67
+ event.preventDefault();
68
+ this.updateTitle();
69
+ this.showSummary();
70
+ this.showInlineErrors();
71
+ }
72
+ }
73
+ showInlineErrors() {
74
+ for (const error of this.errors) {
75
+ this.showInlineError(error);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * @param {ValidationError} error
81
+ */
82
+ showInlineError(error) {
83
+ const $errorSpan = document.createElement('span');
84
+ $errorSpan.id = `${error.fieldName}-error`;
85
+ $errorSpan.classList.add('govuk-error-message');
86
+ $errorSpan.innerHTML = this.escapeHtml(error.message);
87
+ const $control = document.querySelector(`#${error.fieldName}`);
88
+ const $fieldset = $control.closest('.govuk-fieldset');
89
+ const $fieldContainer = ($fieldset || $control).closest('.govuk-form-group');
90
+ const $label = $fieldContainer.querySelector('label');
91
+ const $legend = $fieldContainer.querySelector('legend');
92
+ $fieldContainer.classList.add('govuk-form-group--error');
93
+ if ($fieldset && $legend) {
94
+ $legend.after($errorSpan);
95
+ $fieldContainer.setAttribute('aria-invalid', 'true');
96
+ addAttributeValue($fieldset, 'aria-describedby', $errorSpan.id);
97
+ } else if ($label && $control) {
98
+ $label.after($errorSpan);
99
+ $control.setAttribute('aria-invalid', 'true');
100
+ addAttributeValue($control, 'aria-describedby', $errorSpan.id);
101
+ }
102
+ }
103
+ removeInlineErrors() {
104
+ for (const error of this.errors) {
105
+ this.removeInlineError(error);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * @param {ValidationError} error
111
+ */
112
+ removeInlineError(error) {
113
+ const $errorSpan = document.querySelector(`#${error.fieldName}-error`);
114
+ const $control = document.querySelector(`#${error.fieldName}`);
115
+ const $fieldset = $control.closest('.govuk-fieldset');
116
+ const $fieldContainer = ($fieldset || $control).closest('.govuk-form-group');
117
+ const $label = $fieldContainer.querySelector('label');
118
+ const $legend = $fieldContainer.querySelector('legend');
119
+ $errorSpan.remove();
120
+ $fieldContainer.classList.remove('govuk-form-group--error');
121
+ if ($fieldset && $legend) {
122
+ $fieldContainer.removeAttribute('aria-invalid');
123
+ removeAttributeValue($fieldset, 'aria-describedby', $errorSpan.id);
124
+ } else if ($label && $control) {
125
+ $control.removeAttribute('aria-invalid');
126
+ removeAttributeValue($control, 'aria-describedby', $errorSpan.id);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * @param {string} fieldName - Field name
132
+ * @param {ValidationRule[]} rules - Validation rules
133
+ */
134
+ addValidator(fieldName, rules) {
135
+ this.validators.push({
136
+ fieldName,
137
+ rules,
138
+ field: this.$root.elements.namedItem(fieldName)
139
+ });
140
+ }
141
+ validate() {
142
+ this.errors = [];
143
+
144
+ /** @type {Validator | null} */
145
+ let validator = null;
146
+
147
+ /** @type {boolean | string} */
148
+ let validatorReturnValue = true;
149
+ let i;
150
+ let j;
151
+ for (i = 0; i < this.validators.length; i++) {
152
+ validator = this.validators[i];
153
+ for (j = 0; j < validator.rules.length; j++) {
154
+ validatorReturnValue = validator.rules[j].method(validator.field, validator.rules[j].params);
155
+ if (typeof validatorReturnValue === 'boolean' && !validatorReturnValue) {
156
+ this.errors.push({
157
+ fieldName: validator.fieldName,
158
+ message: validator.rules[j].message
159
+ });
160
+ break;
161
+ } else if (typeof validatorReturnValue === 'string') {
162
+ this.errors.push({
163
+ fieldName: validatorReturnValue,
164
+ message: validator.rules[j].message
165
+ });
166
+ break;
167
+ }
168
+ }
169
+ }
170
+ return this.errors.length === 0;
171
+ }
172
+
173
+ /**
174
+ * @type {Record<string, string>}
175
+ */
11
176
  }
12
177
 
178
+ /**
179
+ * @typedef {object} FormValidatorConfig
180
+ * @property {object} [summary] - Error summary config
181
+ * @property {string} [summary.selector] - Selector for error summary
182
+ * @property {Element | null} [summary.element] - HTML element for error summary
183
+ */
184
+
185
+ /**
186
+ * @typedef {object} ValidationRule
187
+ * @property {(field: Validator['field'], params: Record<string, Validator['field']>) => boolean | string} method - Validation method
188
+ * @property {string} message - Error message
189
+ * @property {Record<string, Validator['field']>} [params] - Parameters for validation
190
+ */
191
+
192
+ /**
193
+ * @typedef {object} ValidationError
194
+ * @property {string} fieldName - Name of the field
195
+ * @property {string} message - Validation error message
196
+ */
197
+
198
+ /**
199
+ * @typedef {object} Validator
200
+ * @property {string} fieldName - Name of the field
201
+ * @property {ValidationRule[]} rules - Validation rules
202
+ * @property {Element | RadioNodeList} field - Form field
203
+ */
204
+
205
+ /**
206
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
207
+ */
13
208
  FormValidator.entityMap = {
14
209
  '&': '&amp;',
15
210
  '<': '&lt;',
@@ -20,150 +215,32 @@ FormValidator.entityMap = {
20
215
  '`': '&#x60;',
21
216
  '=': '&#x3D;'
22
217
  };
23
-
24
- FormValidator.prototype.escapeHtml = function (string) {
25
- return String(string).replace(/[&<>"'`=/]/g, function fromEntityMap(s) {
26
- return FormValidator.entityMap[s]
27
- })
28
- };
29
-
30
- FormValidator.prototype.resetTitle = function () {
31
- document.title = this.originalTitle;
32
- };
33
-
34
- FormValidator.prototype.updateTitle = function () {
35
- document.title = `${this.errors.length} errors - ${document.title}`;
36
- };
37
-
38
- FormValidator.prototype.showSummary = function () {
39
- this.summary.html(this.getSummaryHtml());
40
- this.summary.removeClass('moj-hidden');
41
- this.summary.attr('aria-labelledby', 'errorSummary-heading');
42
- this.summary.focus();
43
- };
44
-
45
- FormValidator.prototype.getSummaryHtml = function () {
46
- let html =
47
- '<h2 id="error-summary-title" class="govuk-error-summary__title">There is a problem</h2>';
48
- html += '<div class="govuk-error-summary__body">';
49
- html += '<ul class="govuk-list govuk-error-summary__list">';
50
- for (let i = 0, j = this.errors.length; i < j; i++) {
51
- const error = this.errors[i];
52
- html += '<li>';
53
- html += `<a href="#${this.escapeHtml(error.fieldName)}">`;
54
- html += this.escapeHtml(error.message);
55
- html += '</a>';
56
- html += '</li>';
57
- }
58
- html += '</ul>';
59
- html += '</div>';
60
- return html
61
- };
62
-
63
- FormValidator.prototype.hideSummary = function () {
64
- this.summary.addClass('moj-hidden');
65
- this.summary.removeAttr('aria-labelledby');
66
- };
67
-
68
- FormValidator.prototype.onSubmit = function (e) {
69
- this.removeInlineErrors();
70
- this.hideSummary();
71
- this.resetTitle();
72
- if (!this.validate()) {
73
- e.preventDefault();
74
- this.updateTitle();
75
- this.showSummary();
76
- this.showInlineErrors();
218
+ /**
219
+ * Name for the component used when initialising using data-module attributes.
220
+ */
221
+ FormValidator.moduleName = 'moj-form-validator';
222
+ /**
223
+ * Multi file upload default config
224
+ *
225
+ * @type {FormValidatorConfig}
226
+ */
227
+ FormValidator.defaults = Object.freeze({
228
+ summary: {
229
+ selector: '.govuk-error-summary'
77
230
  }
78
- };
79
-
80
- FormValidator.prototype.showInlineErrors = function () {
81
- for (let i = 0, j = this.errors.length; i < j; i++) {
82
- this.showInlineError(this.errors[i]);
83
- }
84
- };
85
-
86
- FormValidator.prototype.showInlineError = function (error) {
87
- const errorSpanId = `${error.fieldName}-error`;
88
- const errorSpan = `<span class="govuk-error-message" id="${
89
- errorSpanId
90
- }">${this.escapeHtml(error.message)}</span>`;
91
- const control = $(`#${error.fieldName}`);
92
- const fieldContainer = control.parents('.govuk-form-group');
93
- const label = fieldContainer.find('label');
94
- const legend = fieldContainer.find('legend');
95
- const fieldset = fieldContainer.find('fieldset');
96
- fieldContainer.addClass('govuk-form-group--error');
97
- if (legend.length) {
98
- legend.after(errorSpan);
99
- fieldContainer.attr('aria-invalid', 'true');
100
- addAttributeValue(fieldset[0], 'aria-describedby', errorSpanId);
101
- } else {
102
- label.after(errorSpan);
103
- control.attr('aria-invalid', 'true');
104
- addAttributeValue(control[0], 'aria-describedby', errorSpanId);
105
- }
106
- };
107
-
108
- FormValidator.prototype.removeInlineErrors = function () {
109
- for (let i = 0; i < this.errors.length; i++) {
110
- this.removeInlineError(this.errors[i]);
111
- }
112
- };
113
-
114
- FormValidator.prototype.removeInlineError = function (error) {
115
- const control = $(`#${error.fieldName}`);
116
- const fieldContainer = control.parents('.govuk-form-group');
117
- fieldContainer.find('.govuk-error-message').remove();
118
- fieldContainer.removeClass('govuk-form-group--error');
119
- fieldContainer.find('[aria-invalid]').attr('aria-invalid', 'false');
120
- const errorSpanId = `${error.fieldName}-error`;
121
- removeAttributeValue(
122
- fieldContainer.find('[aria-describedby]')[0],
123
- 'aria-describedby',
124
- errorSpanId
125
- );
126
- };
127
-
128
- FormValidator.prototype.addValidator = function (fieldName, rules) {
129
- this.validators.push({
130
- fieldName,
131
- rules,
132
- field: this.form.elements[fieldName]
133
- });
134
- };
135
-
136
- FormValidator.prototype.validate = function () {
137
- this.errors = [];
138
- let validator = null;
139
- let validatorReturnValue = true;
140
- let i;
141
- let j;
142
- for (i = 0; i < this.validators.length; i++) {
143
- validator = this.validators[i];
144
- for (j = 0; j < validator.rules.length; j++) {
145
- validatorReturnValue = validator.rules[j].method(
146
- validator.field,
147
- validator.rules[j].params
148
- );
149
-
150
- if (typeof validatorReturnValue === 'boolean' && !validatorReturnValue) {
151
- this.errors.push({
152
- fieldName: validator.fieldName,
153
- message: validator.rules[j].message
154
- });
155
- break
156
- } else if (typeof validatorReturnValue === 'string') {
157
- this.errors.push({
158
- fieldName: validatorReturnValue,
159
- message: validator.rules[j].message
160
- });
161
- break
162
- }
231
+ });
232
+ /**
233
+ * Multi file upload config schema
234
+ *
235
+ * @satisfies {Schema<FormValidatorConfig>}
236
+ */
237
+ FormValidator.schema = Object.freeze(/** @type {const} */{
238
+ properties: {
239
+ summary: {
240
+ type: 'object'
163
241
  }
164
242
  }
165
- return this.errors.length === 0
166
- };
243
+ });
167
244
 
168
245
  export { FormValidator };
169
246
  //# sourceMappingURL=form-validator.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"form-validator.mjs","sources":["../../../../src/moj/components/form-validator/form-validator.mjs"],"sourcesContent":["import $ from 'jquery'\n\nimport { addAttributeValue, removeAttributeValue } from '../../helpers.mjs'\n\nexport function FormValidator(form, options) {\n this.form = form\n this.errors = []\n this.validators = []\n $(this.form).on('submit', $.proxy(this, 'onSubmit'))\n this.summary =\n options && options.summary ? $(options.summary) : $('.govuk-error-summary')\n this.originalTitle = document.title\n}\n\nFormValidator.entityMap = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;'\n}\n\nFormValidator.prototype.escapeHtml = function (string) {\n return String(string).replace(/[&<>\"'`=/]/g, function fromEntityMap(s) {\n return FormValidator.entityMap[s]\n })\n}\n\nFormValidator.prototype.resetTitle = function () {\n document.title = this.originalTitle\n}\n\nFormValidator.prototype.updateTitle = function () {\n document.title = `${this.errors.length} errors - ${document.title}`\n}\n\nFormValidator.prototype.showSummary = function () {\n this.summary.html(this.getSummaryHtml())\n this.summary.removeClass('moj-hidden')\n this.summary.attr('aria-labelledby', 'errorSummary-heading')\n this.summary.focus()\n}\n\nFormValidator.prototype.getSummaryHtml = function () {\n let html =\n '<h2 id=\"error-summary-title\" class=\"govuk-error-summary__title\">There is a problem</h2>'\n html += '<div class=\"govuk-error-summary__body\">'\n html += '<ul class=\"govuk-list govuk-error-summary__list\">'\n for (let i = 0, j = this.errors.length; i < j; i++) {\n const error = this.errors[i]\n html += '<li>'\n html += `<a href=\"#${this.escapeHtml(error.fieldName)}\">`\n html += this.escapeHtml(error.message)\n html += '</a>'\n html += '</li>'\n }\n html += '</ul>'\n html += '</div>'\n return html\n}\n\nFormValidator.prototype.hideSummary = function () {\n this.summary.addClass('moj-hidden')\n this.summary.removeAttr('aria-labelledby')\n}\n\nFormValidator.prototype.onSubmit = function (e) {\n this.removeInlineErrors()\n this.hideSummary()\n this.resetTitle()\n if (!this.validate()) {\n e.preventDefault()\n this.updateTitle()\n this.showSummary()\n this.showInlineErrors()\n }\n}\n\nFormValidator.prototype.showInlineErrors = function () {\n for (let i = 0, j = this.errors.length; i < j; i++) {\n this.showInlineError(this.errors[i])\n }\n}\n\nFormValidator.prototype.showInlineError = function (error) {\n const errorSpanId = `${error.fieldName}-error`\n const errorSpan = `<span class=\"govuk-error-message\" id=\"${\n errorSpanId\n }\">${this.escapeHtml(error.message)}</span>`\n const control = $(`#${error.fieldName}`)\n const fieldContainer = control.parents('.govuk-form-group')\n const label = fieldContainer.find('label')\n const legend = fieldContainer.find('legend')\n const fieldset = fieldContainer.find('fieldset')\n fieldContainer.addClass('govuk-form-group--error')\n if (legend.length) {\n legend.after(errorSpan)\n fieldContainer.attr('aria-invalid', 'true')\n addAttributeValue(fieldset[0], 'aria-describedby', errorSpanId)\n } else {\n label.after(errorSpan)\n control.attr('aria-invalid', 'true')\n addAttributeValue(control[0], 'aria-describedby', errorSpanId)\n }\n}\n\nFormValidator.prototype.removeInlineErrors = function () {\n for (let i = 0; i < this.errors.length; i++) {\n this.removeInlineError(this.errors[i])\n }\n}\n\nFormValidator.prototype.removeInlineError = function (error) {\n const control = $(`#${error.fieldName}`)\n const fieldContainer = control.parents('.govuk-form-group')\n fieldContainer.find('.govuk-error-message').remove()\n fieldContainer.removeClass('govuk-form-group--error')\n fieldContainer.find('[aria-invalid]').attr('aria-invalid', 'false')\n const errorSpanId = `${error.fieldName}-error`\n removeAttributeValue(\n fieldContainer.find('[aria-describedby]')[0],\n 'aria-describedby',\n errorSpanId\n )\n}\n\nFormValidator.prototype.addValidator = function (fieldName, rules) {\n this.validators.push({\n fieldName,\n rules,\n field: this.form.elements[fieldName]\n })\n}\n\nFormValidator.prototype.validate = function () {\n this.errors = []\n let validator = null\n let validatorReturnValue = true\n let i\n let j\n for (i = 0; i < this.validators.length; i++) {\n validator = this.validators[i]\n for (j = 0; j < validator.rules.length; j++) {\n validatorReturnValue = validator.rules[j].method(\n validator.field,\n validator.rules[j].params\n )\n\n if (typeof validatorReturnValue === 'boolean' && !validatorReturnValue) {\n this.errors.push({\n fieldName: validator.fieldName,\n message: validator.rules[j].message\n })\n break\n } else if (typeof validatorReturnValue === 'string') {\n this.errors.push({\n fieldName: validatorReturnValue,\n message: validator.rules[j].message\n })\n break\n }\n }\n }\n return this.errors.length === 0\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"form-validator.mjs","sources":["../../../../src/moj/components/form-validator/form-validator.mjs"],"sourcesContent":["import { ConfigurableComponent } from 'govuk-frontend'\n\nimport { addAttributeValue, removeAttributeValue } from '../../helpers.mjs'\n\n/**\n * @augments {ConfigurableComponent<FormValidatorConfig, HTMLFormElement>}\n */\nexport class FormValidator extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for form validator\n * @param {FormValidatorConfig} [config] - Form validator config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $summary =\n this.config.summary.element ||\n document.querySelector(this.config.summary.selector)\n\n if (!$summary || !($summary instanceof HTMLElement)) {\n return this\n }\n\n this.$summary = $summary\n\n this.errors = /** @type {ValidationError[]} */ ([])\n this.validators = /** @type {Validator[]} */ ([])\n this.originalTitle = document.title\n\n this.$root.addEventListener('submit', this.onSubmit.bind(this))\n }\n\n escapeHtml(string = '') {\n return String(string).replace(\n /[&<>\"'`=/]/g,\n (name) => FormValidator.entityMap[name]\n )\n }\n\n resetTitle() {\n document.title = this.originalTitle\n }\n\n updateTitle() {\n document.title = `${this.errors.length} errors - ${document.title}`\n }\n\n showSummary() {\n this.$summary.innerHTML = this.getSummaryHtml()\n this.$summary.classList.remove('moj-hidden')\n this.$summary.setAttribute('aria-labelledby', 'errorSummary-heading')\n this.$summary.focus()\n }\n\n getSummaryHtml() {\n let html =\n '<h2 id=\"error-summary-title\" class=\"govuk-error-summary__title\">There is a problem</h2>'\n html += '<div class=\"govuk-error-summary__body\">'\n html += '<ul class=\"govuk-list govuk-error-summary__list\">'\n for (const error of this.errors) {\n html += '<li>'\n html += `<a href=\"#${this.escapeHtml(error.fieldName)}\">`\n html += this.escapeHtml(error.message)\n html += '</a>'\n html += '</li>'\n }\n html += '</ul>'\n html += '</div>'\n return html\n }\n\n hideSummary() {\n this.$summary.classList.add('moj-hidden')\n this.$summary.removeAttribute('aria-labelledby')\n }\n\n /**\n * @param {SubmitEvent} event - Form submit event\n */\n onSubmit(event) {\n this.removeInlineErrors()\n this.hideSummary()\n this.resetTitle()\n if (!this.validate()) {\n event.preventDefault()\n this.updateTitle()\n this.showSummary()\n this.showInlineErrors()\n }\n }\n\n showInlineErrors() {\n for (const error of this.errors) {\n this.showInlineError(error)\n }\n }\n\n /**\n * @param {ValidationError} error\n */\n showInlineError(error) {\n const $errorSpan = document.createElement('span')\n $errorSpan.id = `${error.fieldName}-error`\n $errorSpan.classList.add('govuk-error-message')\n $errorSpan.innerHTML = this.escapeHtml(error.message)\n\n const $control = document.querySelector(`#${error.fieldName}`)\n const $fieldset = $control.closest('.govuk-fieldset')\n const $fieldContainer = ($fieldset || $control).closest('.govuk-form-group')\n\n const $label = $fieldContainer.querySelector('label')\n const $legend = $fieldContainer.querySelector('legend')\n\n $fieldContainer.classList.add('govuk-form-group--error')\n\n if ($fieldset && $legend) {\n $legend.after($errorSpan)\n $fieldContainer.setAttribute('aria-invalid', 'true')\n addAttributeValue($fieldset, 'aria-describedby', $errorSpan.id)\n } else if ($label && $control) {\n $label.after($errorSpan)\n $control.setAttribute('aria-invalid', 'true')\n addAttributeValue($control, 'aria-describedby', $errorSpan.id)\n }\n }\n\n removeInlineErrors() {\n for (const error of this.errors) {\n this.removeInlineError(error)\n }\n }\n\n /**\n * @param {ValidationError} error\n */\n removeInlineError(error) {\n const $errorSpan = document.querySelector(`#${error.fieldName}-error`)\n\n const $control = document.querySelector(`#${error.fieldName}`)\n const $fieldset = $control.closest('.govuk-fieldset')\n const $fieldContainer = ($fieldset || $control).closest('.govuk-form-group')\n\n const $label = $fieldContainer.querySelector('label')\n const $legend = $fieldContainer.querySelector('legend')\n\n $errorSpan.remove()\n $fieldContainer.classList.remove('govuk-form-group--error')\n\n if ($fieldset && $legend) {\n $fieldContainer.removeAttribute('aria-invalid')\n removeAttributeValue($fieldset, 'aria-describedby', $errorSpan.id)\n } else if ($label && $control) {\n $control.removeAttribute('aria-invalid')\n removeAttributeValue($control, 'aria-describedby', $errorSpan.id)\n }\n }\n\n /**\n * @param {string} fieldName - Field name\n * @param {ValidationRule[]} rules - Validation rules\n */\n addValidator(fieldName, rules) {\n this.validators.push({\n fieldName,\n rules,\n field: this.$root.elements.namedItem(fieldName)\n })\n }\n\n validate() {\n this.errors = []\n\n /** @type {Validator | null} */\n let validator = null\n\n /** @type {boolean | string} */\n let validatorReturnValue = true\n\n let i\n let j\n\n for (i = 0; i < this.validators.length; i++) {\n validator = this.validators[i]\n for (j = 0; j < validator.rules.length; j++) {\n validatorReturnValue = validator.rules[j].method(\n validator.field,\n validator.rules[j].params\n )\n\n if (\n typeof validatorReturnValue === 'boolean' &&\n !validatorReturnValue\n ) {\n this.errors.push({\n fieldName: validator.fieldName,\n message: validator.rules[j].message\n })\n break\n } else if (typeof validatorReturnValue === 'string') {\n this.errors.push({\n fieldName: validatorReturnValue,\n message: validator.rules[j].message\n })\n break\n }\n }\n }\n return this.errors.length === 0\n }\n\n /**\n * @type {Record<string, string>}\n */\n static entityMap = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;'\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-form-validator'\n\n /**\n * Multi file upload default config\n *\n * @type {FormValidatorConfig}\n */\n static defaults = Object.freeze({\n summary: {\n selector: '.govuk-error-summary'\n }\n })\n\n /**\n * Multi file upload config schema\n *\n * @satisfies {Schema<FormValidatorConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n summary: { type: 'object' }\n }\n })\n )\n}\n\n/**\n * @typedef {object} FormValidatorConfig\n * @property {object} [summary] - Error summary config\n * @property {string} [summary.selector] - Selector for error summary\n * @property {Element | null} [summary.element] - HTML element for error summary\n */\n\n/**\n * @typedef {object} ValidationRule\n * @property {(field: Validator['field'], params: Record<string, Validator['field']>) => boolean | string} method - Validation method\n * @property {string} message - Error message\n * @property {Record<string, Validator['field']>} [params] - Parameters for validation\n */\n\n/**\n * @typedef {object} ValidationError\n * @property {string} fieldName - Name of the field\n * @property {string} message - Validation error message\n */\n\n/**\n * @typedef {object} Validator\n * @property {string} fieldName - Name of the field\n * @property {ValidationRule[]} rules - Validation rules\n * @property {Element | RadioNodeList} field - Form field\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["FormValidator","ConfigurableComponent","constructor","$root","config","$summary","summary","element","document","querySelector","selector","HTMLElement","errors","validators","originalTitle","title","addEventListener","onSubmit","bind","escapeHtml","string","String","replace","name","entityMap","resetTitle","updateTitle","length","showSummary","innerHTML","getSummaryHtml","classList","remove","setAttribute","focus","html","error","fieldName","message","hideSummary","add","removeAttribute","event","removeInlineErrors","validate","preventDefault","showInlineErrors","showInlineError","$errorSpan","createElement","id","$control","$fieldset","closest","$fieldContainer","$label","$legend","after","addAttributeValue","removeInlineError","removeAttributeValue","addValidator","rules","push","field","elements","namedItem","validator","validatorReturnValue","i","j","method","params","moduleName","defaults","Object","freeze","schema","properties","type"],"mappings":"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"}
@@ -169,3 +169,5 @@ span.moj-header__link {
169
169
  .moj-header__navigation-link[aria-current="page"] {
170
170
  text-decoration: none;
171
171
  }
172
+
173
+ /*# sourceMappingURL=_header.scss.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/moj/components/header/_header.scss"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,uCAAuC;;AAEvC;;+EAE+E;;AAE/E;EACE,6BAA6B;EAC7B,6CAA6C;EAC7C,uCAAuC;AACzC;;AAEA;EACE,kBAAkB;EAClB,4BAA4B;EAC5B,uBAAuB;AACzB;;AAEA;EACE,gCAAgC;;EAEhC;IACE,WAAW;EACb;AACF;;AAEA;EACE,kBAAkB;EAClB,SAAS;EACT,8BAA8B;EAC9B,mBAAmB;AACrB;;AAEA;EACE,kBAAkB;EAClB,SAAS;EACT,8BAA8B;EAC9B,mBAAmB;AACrB;;AAEA;EACE,gCAAgC;;EAEhC;IACE,YAAY;EACd;AACF;;AAEA;;EAEE,qBAAqB;EACrB,mBAAmB;EACnB,gBAAgB,EAAE,uCAAuC;EACzD,oCAAoC;EACpC,4BAA4B;EAC5B,iBAAiB,EAAE,2CAA2C;EAC9D,sBAAsB;EACtB,0BAA0B;EAC1B,iCAAiC;;EAEjC;;;;IAIE,4BAA4B;IAC5B,qBAAqB;EACvB;;EAEA;IACE,mCAAmC;EACrC;;EAEA;IACE,yBAAyB;IACzB,4BAA4B;EAC9B;;EAEA;IACE,sBAAsB;IACtB,+CAA+C;;IAE/C;MACE,yBAAyB;IAC3B;EACF;;EAEA;IACE,sBAAsB;IACtB,iDAAiD;;IAEjD;MACE,cAAc;IAChB;IACA;MACE,6BAA6B;IAC/B;;IAEA;MACE,yBAAyB;IAC3B;EACF;AACF;;AAEA;EACE,kBAAkB;EAClB,2BAA2B;;EAE3B;IACE,mCAAmC;EACrC;;EAEA;IACE,mBAAmB;IACnB,sBAAsB;EACxB;AACF;AACA,yDAAyD;AACzD;EACE;IACE,yBAAyB;EAC3B;AACF;;AAEA,YAAY;AACZ;EACE,kCAAkC;EAClC,4BAA4B;AAC9B;;AAEA;EACE,SAAS;EACT,UAAU;EACV,YAAY,EAAE,+DAA+D;EAC7E,gBAAgB;AAClB;;AAEA;EACE,qBAAqB;EACrB,8BAA8B;EAC9B,uBAAuB;;EAEvB;IACE,eAAe;EACjB;AACF;;AAEA;EACE,0BAA0B;EAC1B,iCAAiC;;EAEjC;;;IAGE,cAAc;IACd,qBAAqB;EACvB;;EAEA;IACE,sDAAsD;IACtD,qCAAqC;EACvC;;EAEA;IACE,4BAA4B;EAC9B;AACF;;AAEA;EACE,qBAAqB;AACvB","file":"_header.scss","sourcesContent":["@use \"../../objects/width-container\" as *;\n@use \"../../vendor/govuk-frontend\" as *;\n\n/* ==========================================================================\n #HEADER\n ========================================================================== */\n\n.moj-header {\n padding-top: govuk-spacing(3);\n border-bottom: 10px solid $govuk-brand-colour;\n background-color: govuk-colour(\"black\");\n}\n\n.moj-header__container {\n position: relative;\n @include moj-width-container;\n @include govuk-clearfix;\n}\n\n.moj-header__logo {\n padding-bottom: govuk-spacing(1);\n\n @include govuk-media-query($from: desktop) {\n float: left;\n }\n}\n\n.moj-header__logotype-crown {\n position: relative;\n top: -4px;\n margin-right: govuk-spacing(1);\n vertical-align: top;\n}\n\n.moj-header__logotype-crest {\n position: relative;\n top: -8px;\n margin-right: govuk-spacing(1);\n vertical-align: top;\n}\n\n.moj-header__content {\n padding-bottom: govuk-spacing(2);\n\n @include govuk-media-query($from: desktop) {\n float: right;\n }\n}\n\n.moj-header__link,\n.moj-header__link > a {\n display: inline-block;\n margin-bottom: -1px;\n overflow: hidden; // Fixes focus gaps in background colour\n border-bottom: 1px solid transparent;\n color: govuk-colour(\"white\");\n line-height: 25px; // Override due to alignment issue in Chrome\n vertical-align: middle;\n @include govuk-link-common;\n @include govuk-link-style-default;\n\n &:link,\n &:visited,\n &:hover,\n &:active {\n color: govuk-colour(\"white\");\n text-decoration: none;\n }\n\n &:hover {\n border-color: govuk-colour(\"white\");\n }\n\n &:focus {\n border-color: transparent;\n color: govuk-colour(\"black\");\n }\n\n &--organisation-name {\n vertical-align: middle;\n @include govuk-font($size: 24, $weight: \"bold\");\n\n &:hover {\n border-color: transparent;\n }\n }\n\n &--service-name {\n vertical-align: middle;\n @include govuk-font($size: 24, $weight: \"normal\");\n\n @include govuk-media-query($until: desktop) {\n display: block;\n }\n @include govuk-media-query($from: desktop) {\n margin-left: govuk-spacing(1);\n }\n\n &:hover {\n border-color: transparent;\n }\n }\n}\n\n.moj-header__link a {\n margin-bottom: 1px;\n vertical-align: text-bottom;\n\n &:hover {\n border-color: govuk-colour(\"white\");\n }\n\n @include govuk-media-query($until: desktop) {\n margin-bottom: -1px;\n vertical-align: middle;\n }\n}\n// stylelint-disable-next-line selector-no-qualifying-type\nspan.moj-header__link {\n &:hover {\n border-color: transparent;\n }\n}\n\n// Navigation\n.moj-header__navigation {\n margin-top: govuk-spacing(1) - 2px;\n color: govuk-colour(\"white\");\n}\n\n.moj-header__navigation-list {\n margin: 0;\n padding: 0;\n font-size: 0; // Removes white space when using inline-block on child element.\n list-style: none;\n}\n\n.moj-header__navigation-item {\n display: inline-block;\n margin-right: govuk-spacing(4);\n @include govuk-font(19);\n\n &:last-child {\n margin-right: 0;\n }\n}\n\n.moj-header__navigation-link {\n @include govuk-link-common;\n @include govuk-link-style-default;\n\n &:link,\n &:visited,\n &:active {\n color: inherit;\n text-decoration: none;\n }\n\n &:hover {\n // stylelint-disable-next-line declaration-no-important\n text-decoration: underline !important;\n }\n\n &:focus {\n color: govuk-colour(\"black\");\n }\n}\n\n.moj-header__navigation-link[aria-current=\"page\"] {\n text-decoration: none;\n}\n"]}
@@ -64,3 +64,5 @@
64
64
  margin-bottom: 0;
65
65
  }
66
66
  }
67
+
68
+ /*# sourceMappingURL=_identity-bar.scss.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/moj/components/identity-bar/_identity-bar.scss"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,uCAAuC;;AAEvC;;+EAE+E;;AAE/E;EACE,uBAAuB;EACvB,6BAA6B;EAC7B,sCAAsC,EAAE,kCAAkC;EAC1E,4BAA4B;EAC5B,uCAAuC;EACvC,qDAAqD,EAAE,sBAAsB;AAC/E;;AAEA;EACE,YAAY,EAAE,qCAAqC;EACnD,mBAAmB,EAAE,wCAAwC;EAC7D,4BAA4B;;EAE5B;IACE,WAAW;IACX,qBAAqB;IACrB,WAAW;EACb;AACF;;AAEA;EACE,qBAAqB;EACrB,mBAAmB;EACnB,uBAAuB;AACzB;;AAEA;EACE,8BAA8B;EAC9B,6BAA6B;EAC7B,gCAAgC;;EAEhC;IACE,qBAAqB;IACrB,mCAAmC,EAAE,qBAAqB;IAC1D,sCAAsC,EAAE,qBAAqB;IAC7D,mBAAmB;EACrB;AACF;;AAEA;EACE;IACE,qBAAqB;IACrB,sBAAsB;EACxB;AACF;;AAEA;EACE,qBAAqB;EACrB,8BAA8B;;EAE9B;IACE,eAAe;EACjB;;EAEA;IACE,gBAAgB;EAClB;AACF","file":"_identity-bar.scss","sourcesContent":["@use \"../../objects/width-container\" as *;\n@use \"../../vendor/govuk-frontend\" as *;\n\n/* ==========================================================================\n #IDENTITY BAR\n ========================================================================== */\n\n.moj-identity-bar {\n @include govuk-clearfix;\n padding-top: govuk-spacing(2);\n padding-bottom: govuk-spacing(2) - 1px; /* Negative by 1px to compensate */\n color: govuk-colour(\"black\");\n background-color: govuk-colour(\"white\");\n box-shadow: inset 0 -1px 0 0 govuk-colour(\"mid-grey\"); /* Takes up no space */\n}\n\n.moj-identity-bar__container {\n font-size: 0; /* Hide whitespace between elements */\n text-align: justify; /* Trick to remove the need for floats */\n @include moj-width-container;\n\n &::after {\n content: \"\";\n display: inline-block;\n width: 100%;\n }\n}\n\n.moj-identity-bar__title {\n display: inline-block;\n vertical-align: top;\n @include govuk-font(16);\n}\n\n.moj-identity-bar__details {\n margin-right: govuk-spacing(2);\n padding-top: govuk-spacing(1);\n padding-bottom: govuk-spacing(1);\n\n @include govuk-media-query($from: tablet) {\n display: inline-block;\n padding-top: govuk-spacing(2) + 1px; /* Alignment tweaks */\n padding-bottom: govuk-spacing(2) - 1px; /* Alignment tweaks */\n vertical-align: top;\n }\n}\n\n.moj-identity-bar__actions {\n @include govuk-media-query($from: tablet) {\n display: inline-block;\n vertical-align: middle;\n }\n}\n\n.moj-identity-bar__menu {\n display: inline-block;\n margin-right: govuk-spacing(2);\n\n &:last-child {\n margin-right: 0;\n }\n\n .moj-button-menu__toggle-button {\n margin-bottom: 0;\n }\n}\n"]}
@@ -42,3 +42,5 @@
42
42
  }
43
43
  }
44
44
  }
45
+
46
+ /*# sourceMappingURL=_interruption-card.scss.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/moj/components/interruption-card/_interruption-card.scss"],"names":[],"mappings":"AAAA,uCAAuC;;AAEvC;EACE,+BAA+B;EAC/B,6CAA6C;EAC7C,sCAAsC;EACtC,2EAA2E;AAC7E;;AAEA;EACE,gBAAgB;AAClB;;AAEA;;EAEE,4BAA4B;AAC9B;;AAEA,qFAAqF;AACrF,gCAAgC;AAChC;EACE,4BAA4B;EAC5B,mCAAmC;AACrC;;AAEA;EACE,gBAAgB;AAClB;;AAEA;EACE,gBAAgB;;EAEhB;;IAEE,gBAAgB;EAClB;;EAEA;IACE;;MAEE,gBAAgB;IAClB;EACF;AACF","file":"_interruption-card.scss","sourcesContent":["@use \"../../vendor/govuk-frontend\" as *;\n\n.moj-interruption-card {\n margin-bottom: govuk-spacing(3);\n border: $govuk-border-width solid transparent;\n background-color: govuk-colour(\"blue\");\n @include govuk-responsive-padding(7, $adjustment: $govuk-border-width * -1);\n}\n\n.moj-interruption-card__content {\n max-width: 960px;\n}\n\n.moj-interruption-card__heading,\n.moj-interruption-card__body {\n color: govuk-colour(\"white\");\n}\n\n// If $govuk-global-styles is true, we need to override the color and size on elements\n// within the body class directly\n.moj-interruption-card__body > * {\n color: govuk-colour(\"white\");\n @include govuk-font-size($size: 24);\n}\n\n.moj-interruption-card__body:last-child {\n margin-bottom: 0;\n}\n\n.moj-interruption-card__actions:last-child {\n margin-bottom: 0;\n\n .govuk-button:last-child,\n .govuk-link:last-child {\n margin-bottom: 0;\n }\n\n @include govuk-media-query($from: tablet) {\n .govuk-button,\n .govuk-link {\n margin-bottom: 0;\n }\n }\n}\n"]}
@@ -105,3 +105,5 @@
105
105
  @include govuk-font($size: 16, $weight: "bold");
106
106
  }
107
107
  }
108
+
109
+ /*# sourceMappingURL=_messages.scss.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/moj/components/messages/_messages.scss"],"names":[],"mappings":"AAAA,uCAAuC;;AAEvC;;+EAE+E;;AAE/E;EACE,sCAAsC;EACtC,uBAAuB;AACzB;;AAEA;EACE,iBAAiB;EACjB,yBAAyB;EACzB,kBAAkB;EAClB,kBAAkB;;EAElB;IACE,qBAAqB;IACrB,WAAW;IACX,2BAA2B;IAC3B,gCAAgC;IAChC,kBAAkB;IAClB,+CAA+C;EACjD;AACF;;AAEA;EACE,kBAAkB;EAClB,+BAA+B;EAC/B,yBAAyB;EACzB,iCAAiC;;EAEjC;IACE,UAAU;EACZ;;EAEA;IACE,8BAA8B;IAC9B,+BAA+B;IAC/B,YAAY;IACZ,4BAA4B;IAC5B,qCAAqC;IACrC,iBAAiB;;IAEjB;MACE,WAAW;MACX,kBAAkB;MAClB,aAAa;MACb,SAAS;MACT,YAAY;MACZ,aAAa;MACb,0CAA0C;MAC1C,uCAAuC;IACzC;EACF;;EAEA;IACE,6BAA6B;IAC7B,8BAA8B;IAC9B,WAAW;IACX,4CAA4C;;IAE5C;MACE,WAAW;MACX,kBAAkB;MAClB,SAAS;MACT,YAAY;MACZ,YAAY;MACZ,aAAa;MACb,kDAAkD;MAClD,wCAAwC;IAC1C;EACF;AACF;;AAEA;;EAEE,4BAA4B;AAC9B;;AAEA;EACE,+BAA+B;AACjC;;AAEA;EACE;IACE,4BAA4B;;IAE5B;;MAEE,8CAA8C;IAChD;EACF;AACF;;AAEA;EACE,4BAA4B;;EAE5B;IACE,+CAA+C;EACjD;;EAEA;IACE,+CAA+C;EACjD;AACF","file":"_messages.scss","sourcesContent":["@use \"../../vendor/govuk-frontend\" as *;\n\n/* ==========================================================================\n #MESSAGES\n ========================================================================== */\n\n.moj-messages-container {\n border: 1px solid $govuk-border-colour;\n @include govuk-font(19);\n}\n\n.moj-message-list {\n min-height: 200px;\n padding: govuk-spacing(1);\n overflow-x: hidden;\n overflow-y: scroll;\n\n &__date {\n display: inline-block;\n width: 100%;\n padding: govuk-spacing(3) 0;\n color: govuk-colour(\"dark-grey\");\n text-align: center;\n @include govuk-font($size: 19, $weight: \"bold\");\n }\n}\n\n.moj-message-item {\n position: relative;\n margin-bottom: govuk-spacing(1);\n padding: govuk-spacing(3);\n border-radius: 0.5em 0.5em 0.75em;\n\n @include govuk-media-query($from: tablet) {\n width: 50%;\n }\n\n &--sent {\n margin-right: govuk-spacing(2);\n padding-right: govuk-spacing(5);\n float: right;\n color: govuk-colour(\"white\");\n background-color: $govuk-brand-colour;\n text-align: right;\n\n &::after {\n content: \"\";\n position: absolute;\n right: -1.5em;\n bottom: 0;\n width: 1.5em;\n height: 1.5em;\n border-left: 1em solid $govuk-brand-colour;\n border-bottom-left-radius: 1.75em 1.5em;\n }\n }\n\n &--received {\n margin-left: govuk-spacing(2);\n padding-left: govuk-spacing(5);\n float: left;\n background-color: govuk-colour(\"light-grey\");\n\n &::after {\n content: \"\";\n position: absolute;\n bottom: 0;\n left: -1.5em;\n width: 1.5em;\n height: 1.5em;\n border-right: 1em solid govuk-colour(\"light-grey\");\n border-bottom-right-radius: 1.75em 1.5em;\n }\n }\n}\n\n.moj-message-item a:link,\n.moj-message-item a:visited {\n color: govuk-colour(\"white\");\n}\n\n.moj-message-item a:focus {\n color: $govuk-focus-text-colour;\n}\n\n.moj-message-item__text {\n &--sent table {\n color: govuk-colour(\"white\");\n\n & th,\n & td {\n border-bottom: 1px solid govuk-colour(\"white\");\n }\n }\n}\n\n.moj-message-item__meta {\n margin-top: govuk-spacing(2);\n\n &--sender {\n @include govuk-font($size: 16, $weight: \"bold\");\n }\n\n &--timestamp {\n @include govuk-font($size: 16, $weight: \"bold\");\n }\n}\n"]}
@@ -70,3 +70,5 @@
70
70
  float: left;
71
71
  fill: currentcolor;
72
72
  }
73
+
74
+ /*# sourceMappingURL=_multi-file-upload.scss.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/moj/components/multi-file-upload/_multi-file-upload.scss"],"names":[],"mappings":"AAAA,uCAAuC;;AAEvC;EACE,mBAAmB;AACrB;;AAEA;EACE,aAAa;AACf;;AAEA;EACE,aAAa;EACb,0CAA0C;EAC1C;;gCAE8B;EAC9B,yCAAyC;EACzC,kBAAkB;AACpB;;AAEA;EACE,qBAAqB;EACrB,WAAW;EACX,gBAAgB;AAClB;;AAEA;EACE,kBAAkB;EAClB,gBAAgB;EAChB,gBAAgB;AAClB;;AAEA;EACE,kBAAkB;EAClB,aAAa;AACf;;AAEA;EACE,sBAAsB;EACtB,mBAAmB;AACrB;;AAEA;EACE,aAAa;EACb,+BAA+B;EAC/B,qCAAqC;EACrC;;kCAEgC;AAClC;;AAEA;EACE,0BAA0B;EAC1B,iBAAiB;AACnB;;AAEA;EACE,4BAA4B;EAC5B,iBAAiB;AACnB;;AAEA;EACE,8BAA8B;EAC9B,WAAW;EACX,kBAAkB;AACpB;;AAEA;EACE,8BAA8B;EAC9B,WAAW;EACX,kBAAkB;AACpB","file":"_multi-file-upload.scss","sourcesContent":["@use \"../../vendor/govuk-frontend\" as *;\n\n.moj-multi-file-upload {\n margin-bottom: 40px;\n}\n\n.moj-multi-file-upload--enhanced .moj-multi-file-upload__button {\n display: none;\n}\n\n.moj-multi-file-upload__dropzone {\n display: flex;\n padding: govuk-spacing(9) govuk-spacing(3);\n transition:\n outline-offset 0.1s ease-in-out,\n background-color 0.1s linear;\n outline: 3px dashed govuk-colour(\"black\");\n text-align: center;\n}\n\n.moj-multi-file-upload__dropzone label {\n display: inline-block;\n width: auto;\n margin-bottom: 0;\n}\n\n.moj-multi-file-upload__dropzone p {\n margin-right: 10px;\n margin-bottom: 0;\n padding-top: 7px;\n}\n\n.moj-multi-file-upload__dropzone [type=\"file\"] {\n position: absolute;\n left: -9999em;\n}\n\n.moj-multi-file-upload--dragover {\n outline-color: #6f777b;\n background: #b1b4b6;\n}\n\n.moj-multi-file-upload--focused {\n outline: none;\n color: $govuk-focus-text-colour;\n background-color: $govuk-focus-colour;\n box-shadow:\n 0 -2px $govuk-focus-colour,\n 0 4px $govuk-focus-text-colour;\n}\n\n.moj-multi-file-upload__error {\n color: govuk-colour(\"red\");\n font-weight: bold;\n}\n\n.moj-multi-file-upload__success {\n color: govuk-colour(\"green\");\n font-weight: bold;\n}\n\n.moj-multi-file-upload__error svg {\n margin-right: govuk-spacing(2);\n float: left;\n fill: currentcolor;\n}\n\n.moj-multi-file-upload__success svg {\n margin-right: govuk-spacing(2);\n float: left;\n fill: currentcolor;\n}\n"]}