@ministryofjustice/frontend 3.3.1 → 3.5.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 (83) hide show
  1. package/README.md +4 -10
  2. package/govuk-prototype-kit.config.json +5 -16
  3. package/moj/all.jquery.min.js +15 -4
  4. package/moj/all.js +2856 -2280
  5. package/moj/all.scss +2 -0
  6. package/moj/components/_all.scss +1 -0
  7. package/moj/components/action-bar/_action-bar.scss +4 -6
  8. package/moj/components/add-another/_add-another.scss +9 -7
  9. package/moj/components/add-another/add-another.js +128 -76
  10. package/moj/components/alert/README.md +0 -0
  11. package/moj/components/alert/_alert.scss +142 -0
  12. package/moj/components/alert/alert.js +482 -0
  13. package/moj/components/alert/alert.spec.helper.js +92 -0
  14. package/moj/components/alert/macro.njk +3 -0
  15. package/moj/components/alert/template.njk +83 -0
  16. package/moj/components/badge/_badge.scss +3 -4
  17. package/moj/components/banner/_banner.scss +5 -10
  18. package/moj/components/button-menu/_button-menu.scss +10 -9
  19. package/moj/components/button-menu/button-menu.js +348 -318
  20. package/moj/components/cookie-banner/_cookie-banner.scss +6 -5
  21. package/moj/components/currency-input/_currency-input.scss +4 -4
  22. package/moj/components/date-picker/README.md +14 -17
  23. package/moj/components/date-picker/_date-picker.scss +122 -106
  24. package/moj/components/date-picker/date-picker.js +927 -900
  25. package/moj/components/filter/README.md +1 -1
  26. package/moj/components/filter/_filter.scss +53 -75
  27. package/moj/components/filter-toggle-button/filter-toggle-button.js +122 -87
  28. package/moj/components/form-validator/form-validator.js +399 -156
  29. package/moj/components/header/_header.scss +17 -19
  30. package/moj/components/identity-bar/_identity-bar.scss +5 -5
  31. package/moj/components/interruption-card/_interruption-card.scss +2 -2
  32. package/moj/components/messages/_messages.scss +12 -19
  33. package/moj/components/multi-file-upload/README.md +1 -1
  34. package/moj/components/multi-file-upload/_multi-file-upload.scss +34 -30
  35. package/moj/components/multi-file-upload/multi-file-upload.js +454 -183
  36. package/moj/components/multi-select/_multi-select.scss +4 -3
  37. package/moj/components/multi-select/multi-select.js +106 -70
  38. package/moj/components/notification-badge/_notification-badge.scss +12 -12
  39. package/moj/components/organisation-switcher/_organisation-switcher.scss +1 -1
  40. package/moj/components/page-header-actions/_page-header-actions.scss +3 -2
  41. package/moj/components/pagination/_pagination.scss +26 -31
  42. package/moj/components/password-reveal/_password-reveal.scss +1 -2
  43. package/moj/components/password-reveal/password-reveal.js +63 -31
  44. package/moj/components/primary-navigation/_primary-navigation.scss +26 -29
  45. package/moj/components/progress-bar/_progress-bar.scss +21 -26
  46. package/moj/components/rich-text-editor/_rich-text-editor.scss +17 -16
  47. package/moj/components/rich-text-editor/rich-text-editor.js +186 -139
  48. package/moj/components/search/_search.scss +6 -4
  49. package/moj/components/search-toggle/search-toggle.js +83 -53
  50. package/moj/components/search-toggle/search-toggle.scss +21 -15
  51. package/moj/components/side-navigation/_side-navigation.scss +12 -21
  52. package/moj/components/sortable-table/_sortable-table.scss +25 -23
  53. package/moj/components/sortable-table/sortable-table.js +162 -119
  54. package/moj/components/sub-navigation/_sub-navigation.scss +24 -28
  55. package/moj/components/tag/_tag.scss +8 -9
  56. package/moj/components/task-list/_task-list.scss +8 -7
  57. package/moj/components/ticket-panel/_ticket-panel.scss +14 -6
  58. package/moj/components/timeline/_timeline.scss +18 -20
  59. package/moj/filters/all.js +28 -30
  60. package/moj/filters/prototype-kit-13-filters.js +2 -1
  61. package/moj/helpers/_all.scss +1 -0
  62. package/moj/helpers/_hidden.scss +1 -1
  63. package/moj/helpers/_links.scss +20 -0
  64. package/moj/helpers.js +218 -51
  65. package/moj/init.js +2 -2
  66. package/moj/moj-frontend.min.css +2 -2
  67. package/moj/moj-frontend.min.js +15 -4
  68. package/moj/objects/_filter-layout.scss +11 -10
  69. package/moj/objects/_scrollable-pane.scss +11 -14
  70. package/moj/settings/_colours.scss +5 -0
  71. package/moj/settings/_measurements.scss +0 -2
  72. package/moj/utilities/_hidden.scss +3 -3
  73. package/moj/utilities/_width-container.scss +1 -1
  74. package/moj/version.js +28 -1
  75. package/package.json +1 -1
  76. package/moj/all.spec.js +0 -22
  77. package/moj/components/button-menu/button-menu.spec.js +0 -361
  78. package/moj/components/date-picker/date-picker.spec.js +0 -1130
  79. package/moj/components/filter-toggle-button/filter-toggle-button.spec.js +0 -304
  80. package/moj/components/multi-select/multi-select.spec.js +0 -135
  81. package/moj/components/password-reveal/password-reveal.spec.js +0 -55
  82. package/moj/components/search-toggle/search-toggle.spec.js +0 -134
  83. package/moj/namespace.js +0 -1
@@ -3,44 +3,43 @@
3
3
  ========================================================================== */
4
4
 
5
5
  .moj-timeline {
6
+ position: relative;
6
7
  margin-bottom: govuk-spacing(4);
7
8
  overflow: hidden;
8
- position: relative;
9
9
 
10
- &:before {
11
- background-color: $govuk-brand-colour;
10
+ &::before {
12
11
  content: "";
13
- height: 100%;
14
- left: 0;
15
12
  position: absolute;
16
13
  top: govuk-spacing(2);
14
+ left: 0;
17
15
  width: 5px;
16
+ height: 100%;
17
+ background-color: $govuk-brand-colour;
18
18
  }
19
-
20
19
  }
21
20
 
22
21
  .moj-timeline--full {
23
22
  margin-bottom: 0;
24
- &:before {
23
+
24
+ &::before {
25
25
  height: calc(100% - 75px);
26
26
  }
27
27
  }
28
28
 
29
29
  .moj-timeline__item {
30
+ position: relative;
30
31
  padding-bottom: govuk-spacing(6);
31
32
  padding-left: govuk-spacing(4);
32
- position: relative;
33
33
 
34
- &:before {
35
- background-color: $govuk-brand-colour;
34
+ &::before {
36
35
  content: "";
37
- height: 5px;
38
- left: 0;
39
36
  position: absolute;
40
37
  top: govuk-spacing(2);
38
+ left: 0;
41
39
  width: 15px;
40
+ height: 5px;
41
+ background-color: $govuk-brand-colour;
42
42
  }
43
-
44
43
  }
45
44
 
46
45
  .moj-timeline__title {
@@ -50,9 +49,9 @@
50
49
 
51
50
  .moj-timeline__byline {
52
51
  @include govuk-font($size: 19);
53
- color: $govuk-secondary-text-colour;
54
52
  display: inline;
55
53
  margin: 0;
54
+ color: $govuk-secondary-text-colour;
56
55
  }
57
56
 
58
57
  .moj-timeline__date {
@@ -71,9 +70,9 @@
71
70
  ========================================================================== */
72
71
 
73
72
  .moj-timeline__documents {
74
- list-style: none;
75
73
  margin-bottom: 0;
76
74
  padding-left: 0;
75
+ list-style: none;
77
76
  }
78
77
 
79
78
  .moj-timeline__document-item {
@@ -82,14 +81,13 @@
82
81
  &:last-child {
83
82
  margin-bottom: 0;
84
83
  }
85
-
86
84
  }
87
85
 
88
86
  .moj-timeline__document-icon {
89
- float: left;
90
87
  margin-top: 4px;
91
88
  margin-right: 4px;
92
- fill: currentColor;
89
+ float: left;
90
+ fill: currentcolor;
93
91
 
94
92
  @media screen and (forced-colors: active) {
95
93
  fill: linkText;
@@ -97,11 +95,11 @@
97
95
  }
98
96
 
99
97
  .moj-timeline__document-link {
98
+ padding-left: govuk-spacing(5);
100
99
  background-image: url(#{$moj-images-path}icon-document.svg);
101
100
  background-repeat: no-repeat;
102
- background-size: 20px 16px;
103
101
  background-position: 0 50%;
104
- padding-left: govuk-spacing(5);
102
+ background-size: 20px 16px;
105
103
 
106
104
  &:focus {
107
105
  color: govuk-colour("black"); // Focus colour on yellow should really be black.
@@ -1,41 +1,41 @@
1
- const moment = require('moment');
1
+ const moment = require('moment')
2
2
 
3
3
  module.exports = function () {
4
4
  /**
5
5
  * Instantiate object used to store the methods registered as a
6
6
  * 'filter' (of the same name) within nunjucks. You can override
7
7
  * gov.uk core filters by creating filter methods of the same name.
8
- * @type {Object}
8
+ *
9
+ * @type {object}
9
10
  */
10
- let filters = {}
11
+ const filters = {}
11
12
 
12
13
  /* ------------------------------------------------------------------
13
14
  date filter for use in Nunjucks
14
15
  example: {{ params.date | date("DD/MM/YYYY") }}
15
16
  outputs: 01/01/1970
16
17
  ------------------------------------------------------------------ */
17
- filters.date = function(timestamp, format) {
18
- return moment(timestamp).format(format);
18
+ filters.date = function (timestamp, format) {
19
+ return moment(timestamp).format(format)
19
20
  }
20
21
 
21
22
  /* ------------------------------------------------------------------
22
23
  utility functions for use in mojDate function/filter
23
24
  ------------------------------------------------------------------ */
24
25
  function govDate(timestamp) {
25
- return moment(timestamp).format('D MMMM YYYY');
26
+ return moment(timestamp).format('D MMMM YYYY')
26
27
  }
27
-
28
+
28
29
  function govShortDate(timestamp) {
29
- return moment(timestamp).format('D MMM YYYY');
30
+ return moment(timestamp).format('D MMM YYYY')
30
31
  }
31
-
32
+
32
33
  function govTime(timestamp) {
33
- let t = moment(timestamp);
34
- if(t.minutes() > 0) {
35
- return t.format('h:mma');
36
- } else {
37
- return t.format('ha');
34
+ const t = moment(timestamp)
35
+ if (t.minutes() > 0) {
36
+ return t.format('h:mma')
38
37
  }
38
+ return t.format('ha')
39
39
  }
40
40
 
41
41
  /* ------------------------------------------------------------------
@@ -43,27 +43,25 @@ module.exports = function () {
43
43
  example: {{ params.date | mojDate("datetime") }}
44
44
  outputs: 1 Jan 1970 at 1:32pm
45
45
  ------------------------------------------------------------------ */
46
- filters.mojDate = function(timestamp, type) {
47
-
48
- switch(type) {
49
- case "datetime":
50
- return govDate(timestamp) + " at " + govTime(timestamp);
51
- case "shortdatetime":
52
- return govShortDate(timestamp) + " at " + govTime(timestamp);
53
- case "date":
54
- return govDate(timestamp);
55
- case "shortdate":
56
- return govShortDate(timestamp);
57
- case "time":
58
- return govTime(timestamp);
46
+ filters.mojDate = function (timestamp, type) {
47
+ switch (type) {
48
+ case 'datetime':
49
+ return `${govDate(timestamp)} at ${govTime(timestamp)}`
50
+ case 'shortdatetime':
51
+ return `${govShortDate(timestamp)} at ${govTime(timestamp)}`
52
+ case 'date':
53
+ return govDate(timestamp)
54
+ case 'shortdate':
55
+ return govShortDate(timestamp)
56
+ case 'time':
57
+ return govTime(timestamp)
59
58
  default:
60
- return timestamp;
59
+ return timestamp
61
60
  }
62
-
63
61
  }
64
62
 
65
63
  /* ------------------------------------------------------------------
66
64
  keep the following line to return your filters to the app
67
65
  ------------------------------------------------------------------ */
68
- return filters;
66
+ return filters
69
67
  }
@@ -1,8 +1,9 @@
1
1
  const { addFilter } = require('govuk-prototype-kit').views
2
+
2
3
  const getAllFilters = require('./all')
3
4
 
4
5
  const allFilters = getAllFilters()
5
6
 
6
- Object.keys(allFilters).forEach(name => {
7
+ Object.keys(allFilters).forEach((name) => {
7
8
  addFilter(name, allFilters[name])
8
9
  })
@@ -1 +1,2 @@
1
1
  @import "hidden";
2
+ @import "links";
@@ -1,3 +1,3 @@
1
1
  @mixin moj-hidden() {
2
2
  display: none;
3
- }
3
+ }
@@ -0,0 +1,20 @@
1
+ @import "../settings/colours";
2
+
3
+ @mixin moj-link-style-warning {
4
+ &:link,
5
+ &:visited {
6
+ color: $moj-warning-link-colour;
7
+ }
8
+
9
+ &:hover {
10
+ color: scale-color($moj-warning-link-colour, $lightness: -30%);
11
+ }
12
+
13
+ &:active {
14
+ color: $moj-warning-colour;
15
+ }
16
+
17
+ &:focus {
18
+ color: $govuk-focus-text-colour;
19
+ }
20
+ }
package/moj/helpers.js CHANGED
@@ -1,51 +1,218 @@
1
- MOJFrontend.removeAttributeValue = function(el, attr, value) {
2
- var re, m;
3
- if (el.getAttribute(attr)) {
4
- if (el.getAttribute(attr) == value) {
5
- el.removeAttribute(attr);
6
- } else {
7
- re = new RegExp('(^|\\s)' + value + '(\\s|$)');
8
- m = el.getAttribute(attr).match(re);
9
- if (m && m.length == 3) {
10
- el.setAttribute(attr, el.getAttribute(attr).replace(re, (m[1] && m[2])?' ':''))
11
- }
12
- }
13
- }
14
- }
15
-
16
- MOJFrontend.addAttributeValue = function(el, attr, value) {
17
- var re;
18
- if (!el.getAttribute(attr)) {
19
- el.setAttribute(attr, value);
20
- }
21
- else {
22
- re = new RegExp('(^|\\s)' + value + '(\\s|$)');
23
- if (!re.test(el.getAttribute(attr))) {
24
- el.setAttribute(attr, el.getAttribute(attr) + ' ' + value);
25
- }
26
- }
27
- };
28
-
29
- MOJFrontend.dragAndDropSupported = function() {
30
- var div = document.createElement('div');
31
- return typeof div.ondrop != 'undefined';
32
- };
33
-
34
- MOJFrontend.formDataSupported = function() {
35
- return typeof FormData == 'function';
36
- };
37
-
38
- MOJFrontend.fileApiSupported = function() {
39
- var input = document.createElement('input');
40
- input.type = 'file';
41
- return typeof input.files != 'undefined';
42
- };
43
-
44
- MOJFrontend.nodeListForEach = function(nodes, callback) {
45
- if (window.NodeList.prototype.forEach) {
46
- return nodes.forEach(callback)
47
- }
48
- for (var i = 0; i < nodes.length; i++) {
49
- callback.call(window, nodes[i], i, nodes)
50
- }
51
- };
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
+ typeof define === 'function' && define.amd ? define(factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.MOJFrontend = factory());
5
+ })(this, (function () { 'use strict';
6
+
7
+ function getDefaultExportFromCjs (x) {
8
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
9
+ }
10
+
11
+ var helpers$1;
12
+ var hasRequiredHelpers;
13
+
14
+ function requireHelpers () {
15
+ if (hasRequiredHelpers) return helpers$1;
16
+ hasRequiredHelpers = 1;
17
+ function removeAttributeValue(el, attr, value) {
18
+ let re, m;
19
+ if (el.getAttribute(attr)) {
20
+ if (el.getAttribute(attr) === value) {
21
+ el.removeAttribute(attr);
22
+ } else {
23
+ re = new RegExp(`(^|\\s)${value}(\\s|$)`);
24
+ m = el.getAttribute(attr).match(re);
25
+ if (m && m.length === 3) {
26
+ el.setAttribute(
27
+ attr,
28
+ el.getAttribute(attr).replace(re, m[1] && m[2] ? ' ' : '')
29
+ );
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ function addAttributeValue(el, attr, value) {
36
+ let re;
37
+ if (!el.getAttribute(attr)) {
38
+ el.setAttribute(attr, value);
39
+ } else {
40
+ re = new RegExp(`(^|\\s)${value}(\\s|$)`);
41
+ if (!re.test(el.getAttribute(attr))) {
42
+ el.setAttribute(attr, `${el.getAttribute(attr)} ${value}`);
43
+ }
44
+ }
45
+ }
46
+
47
+ function dragAndDropSupported() {
48
+ const div = document.createElement('div');
49
+ return typeof div.ondrop !== 'undefined'
50
+ }
51
+
52
+ function formDataSupported() {
53
+ return typeof FormData === 'function'
54
+ }
55
+
56
+ function fileApiSupported() {
57
+ const input = document.createElement('input');
58
+ input.type = 'file';
59
+ return typeof input.files !== 'undefined'
60
+ }
61
+
62
+ function nodeListForEach(nodes, callback) {
63
+ if (window.NodeList.prototype.forEach) {
64
+ return nodes.forEach(callback)
65
+ }
66
+ for (let i = 0; i < nodes.length; i++) {
67
+ callback.call(window, nodes[i], i, nodes);
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Find an elements next sibling
73
+ *
74
+ * Utility function to find an elements next sibling matching the provided
75
+ * selector.
76
+ *
77
+ * @param {HTMLElement} $element - Element to find siblings for
78
+ * @param {string} selector - selector for required sibling
79
+ */
80
+ function getNextSibling($element, selector) {
81
+ if (!$element) return
82
+ // Get the next sibling element
83
+ let $sibling = $element.nextElementSibling;
84
+
85
+ // If there's no selector, return the first sibling
86
+ if (!selector) return $sibling
87
+
88
+ // If the sibling matches our selector, use it
89
+ // If not, jump to the next sibling and continue the loop
90
+ while ($sibling) {
91
+ if ($sibling.matches(selector)) return $sibling
92
+ $sibling = $sibling.nextElementSibling;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Find an elements preceding sibling
98
+ *
99
+ * Utility function to find an elements previous sibling matching the provided
100
+ * selector.
101
+ *
102
+ * @param {HTMLElement} $element - Element to find siblings for
103
+ * @param {string} selector - selector for required sibling
104
+ */
105
+ function getPreviousSibling($element, selector) {
106
+ if (!$element) return
107
+ // Get the previous sibling element
108
+ let $sibling = $element.previousElementSibling;
109
+
110
+ // If there's no selector, return the first sibling
111
+ if (!selector) return $sibling
112
+
113
+ // If the sibling matches our selector, use it
114
+ // If not, jump to the next sibling and continue the loop
115
+ while ($sibling) {
116
+ if ($sibling.matches(selector)) return $sibling
117
+ $sibling = $sibling.previousElementSibling;
118
+ }
119
+ }
120
+
121
+ function findNearestMatchingElement($element, selector) {
122
+ // If no element or selector is provided, return null
123
+ if (!$element) return
124
+ if (!selector) return
125
+
126
+ // Start with the current element
127
+ let $currentElement = $element;
128
+
129
+ while ($currentElement) {
130
+ // First check the current element
131
+ if ($currentElement.matches(selector)) {
132
+ return $currentElement
133
+ }
134
+
135
+ // Check all previous siblings
136
+ let $sibling = $currentElement.previousElementSibling;
137
+ while ($sibling) {
138
+ // Check if the sibling itself is a heading
139
+ if ($sibling.matches(selector)) {
140
+ return $sibling
141
+ }
142
+ $sibling = $sibling.previousElementSibling;
143
+ }
144
+
145
+ // If no match found in siblings, move up to parent
146
+ $currentElement = $currentElement.parentElement;
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Move focus to element
152
+ *
153
+ * Sets tabindex to -1 to make the element programmatically focusable,
154
+ * but removes it on blur as the element doesn't need to be focused again.
155
+ *
156
+ * @param {HTMLElement} $element - HTML element
157
+ * @param {object} [options] - Handler options
158
+ * @param {function(this: HTMLElement): void} [options.onBeforeFocus] - Callback before focus
159
+ * @param {function(this: HTMLElement): void} [options.onBlur] - Callback on blur
160
+ */
161
+ function setFocus($element, options = {}) {
162
+ const isFocusable = $element.getAttribute('tabindex');
163
+
164
+ if (!isFocusable) {
165
+ $element.setAttribute('tabindex', '-1');
166
+ }
167
+
168
+ /**
169
+ * Handle element focus
170
+ */
171
+ function onFocus() {
172
+ $element.addEventListener('blur', onBlur, { once: true });
173
+ }
174
+
175
+ /**
176
+ * Handle element blur
177
+ */
178
+ function onBlur() {
179
+ if (options.onBlur) {
180
+ options.onBlur.call($element);
181
+ }
182
+
183
+ if (!isFocusable) {
184
+ $element.removeAttribute('tabindex');
185
+ }
186
+ }
187
+
188
+ // Add listener to reset element on blur, after focus
189
+ $element.addEventListener('focus', onFocus, { once: true });
190
+
191
+ // Focus element
192
+ if (options.onBeforeFocus) {
193
+ options.onBeforeFocus.call($element);
194
+ }
195
+ $element.focus();
196
+ }
197
+
198
+ helpers$1 = {
199
+ removeAttributeValue,
200
+ addAttributeValue,
201
+ dragAndDropSupported,
202
+ formDataSupported,
203
+ fileApiSupported,
204
+ nodeListForEach,
205
+ getNextSibling,
206
+ getPreviousSibling,
207
+ findNearestMatchingElement,
208
+ setFocus
209
+ };
210
+ return helpers$1;
211
+ }
212
+
213
+ var helpersExports = requireHelpers();
214
+ var helpers = /*@__PURE__*/getDefaultExportFromCjs(helpersExports);
215
+
216
+ return helpers;
217
+
218
+ }));
package/moj/init.js CHANGED
@@ -1,5 +1,5 @@
1
1
  if (window.GOVUKPrototypeKit && window.GOVUKPrototypeKit.documentReady) {
2
2
  window.GOVUKPrototypeKit.documentReady(function () {
3
- window.MOJFrontend.initAll();
4
- });
3
+ window.MOJFrontend.initAll()
4
+ })
5
5
  }