@ons/design-system 44.0.1 → 45.0.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 (165) hide show
  1. package/components/access-code/uac.scss +5 -5
  2. package/components/address-input/_macro.njk +1 -0
  3. package/components/address-input/autosuggest.address.js +0 -1
  4. package/components/autosuggest/_macro.njk +1 -0
  5. package/components/autosuggest/autosuggest.ui.js +3 -3
  6. package/components/autosuggest/{code.list.searcher.js → fuse-config.js} +1 -3
  7. package/components/checkboxes/_checkbox-macro.njk +1 -1
  8. package/components/checkboxes/_macro.njk +1 -1
  9. package/components/fieldset/_macro.njk +1 -1
  10. package/components/header/_header.scss +3 -4
  11. package/components/header/_macro.njk +2 -2
  12. package/components/highlight/_highlight.scss +5 -0
  13. package/components/input/_input.scss +2 -2
  14. package/components/metadata/_macro.njk +1 -1
  15. package/components/metadata/_metadata.scss +1 -1
  16. package/components/modal/_macro.njk +23 -0
  17. package/components/modal/_modal.scss +32 -0
  18. package/components/modal/modal.dom.js +14 -0
  19. package/components/modal/modal.js +104 -0
  20. package/components/radios/_macro.njk +2 -2
  21. package/components/table-of-contents/_macro.njk +7 -7
  22. package/components/textarea/_macro.njk +2 -2
  23. package/components/timeout-modal/_macro.njk +26 -0
  24. package/components/timeout-modal/timeout.dom.js +16 -0
  25. package/components/timeout-modal/timeout.js +289 -0
  26. package/css/census.css +1 -0
  27. package/css/error.css +1 -0
  28. package/css/main.css +1 -0
  29. package/css/print.css +1 -0
  30. package/favicons/android-chrome-192x192.png +0 -0
  31. package/favicons/android-chrome-512x512.png +0 -0
  32. package/favicons/apple-touch-icon.png +0 -0
  33. package/favicons/browserconfig.xml +12 -0
  34. package/favicons/census/cy/android-chrome-192x192.png +0 -0
  35. package/favicons/census/cy/android-chrome-512x512.png +0 -0
  36. package/favicons/census/cy/apple-touch-icon.png +0 -0
  37. package/favicons/census/cy/browserconfig.xml +12 -0
  38. package/favicons/census/cy/favicon-16x16.png +0 -0
  39. package/favicons/census/cy/favicon-32x32.png +0 -0
  40. package/favicons/census/cy/favicon.ico +0 -0
  41. package/favicons/census/cy/manifest.json +20 -0
  42. package/favicons/census/cy/mstitle-150x150.png +0 -0
  43. package/favicons/census/cy/mstitle-310x150.png +0 -0
  44. package/favicons/census/cy/mstitle-310x310.png +0 -0
  45. package/favicons/census/cy/mstitle-70x70.png +0 -0
  46. package/favicons/census/cy/opengraph.png +0 -0
  47. package/favicons/census/cy/safari-pinned-tab.svg +3 -0
  48. package/favicons/census/cy/site.webmanifest +19 -0
  49. package/favicons/census/cy/twitter.png +0 -0
  50. package/favicons/census/en/android-chrome-192x192.png +0 -0
  51. package/favicons/census/en/android-chrome-512x512.png +0 -0
  52. package/favicons/census/en/apple-touch-icon.png +0 -0
  53. package/favicons/census/en/browserconfig.xml +12 -0
  54. package/favicons/census/en/favicon-16x16.png +0 -0
  55. package/favicons/census/en/favicon-32x32.png +0 -0
  56. package/favicons/census/en/favicon.ico +0 -0
  57. package/favicons/census/en/manifest.json +20 -0
  58. package/favicons/census/en/mstitle-150x150.png +0 -0
  59. package/favicons/census/en/mstitle-310x150.png +0 -0
  60. package/favicons/census/en/mstitle-310x310.png +0 -0
  61. package/favicons/census/en/mstitle-70x70.png +0 -0
  62. package/favicons/census/en/opengraph.png +0 -0
  63. package/favicons/census/en/safari-pinned-tab.svg +3 -0
  64. package/favicons/census/en/site.webmanifest +19 -0
  65. package/favicons/census/en/twitter.png +0 -0
  66. package/favicons/census/ni/favicon.ico +0 -0
  67. package/favicons/favicon-16x16.png +0 -0
  68. package/favicons/favicon-32x32.png +0 -0
  69. package/favicons/favicon.ico +0 -0
  70. package/favicons/manifest.json +27 -0
  71. package/favicons/maskable_icon.png +0 -0
  72. package/favicons/mstitle-150x150.png +0 -0
  73. package/favicons/mstitle-310x150.png +0 -0
  74. package/favicons/mstitle-310x310.png +0 -0
  75. package/favicons/mstitle-70x70.png +0 -0
  76. package/favicons/opengraph.png +0 -0
  77. package/favicons/safari-pinned-tab.svg +25 -0
  78. package/favicons/site.webmanifest +19 -0
  79. package/favicons/twitter.png +0 -0
  80. package/fonts/opensans-bold.woff +0 -0
  81. package/fonts/opensans-bold.woff2 +0 -0
  82. package/fonts/opensans-regular.woff +0 -0
  83. package/fonts/opensans-regular.woff2 +0 -0
  84. package/fonts/robotomono-bold.woff +0 -0
  85. package/fonts/robotomono-bold.woff2 +0 -0
  86. package/fonts/robotomono-regular.woff +0 -0
  87. package/fonts/robotomono-regular.woff2 +0 -0
  88. package/img/UKOpenGovernmentLicence-grey.svg +1 -0
  89. package/img/UKOpenGovernmentLicence.svg +1 -0
  90. package/img/card-placeholder.svg +1 -0
  91. package/img/census-landscape.svg +1 -0
  92. package/img/census-promo-banner.svg +1 -0
  93. package/img/circle-lines.svg +1 -0
  94. package/img/icons--check.svg +1 -0
  95. package/img/icons--chevron-down.svg +1 -0
  96. package/img/its-about-us--dark.svg +1 -0
  97. package/img/its-about-us--light.svg +1 -0
  98. package/img/large/hero-man.png +0 -0
  99. package/img/large/mother-and-daughter-in-ireland.jpg +0 -0
  100. package/img/large/mum-and-child-healthcare-belfast.jpg +0 -0
  101. package/img/large/placeholder-card.png +0 -0
  102. package/img/large/placeholder-news-medium.png +0 -0
  103. package/img/large/placeholder-news.png +0 -0
  104. package/img/large/placeholder-portrait.png +0 -0
  105. package/img/large/students.jpg +0 -0
  106. package/img/large/woman-in-purple-dress-shirt.jpg +0 -0
  107. package/img/logo.svg +1 -0
  108. package/img/ni-syn-cyfrif--dark.svg +1 -0
  109. package/img/ni-syn-cyfrif--light.svg +1 -0
  110. package/img/nisra-logo-black-en.svg +1 -0
  111. package/img/ogl.svg +1 -0
  112. package/img/ons-logo-black-cy.svg +1 -0
  113. package/img/ons-logo-black-en.svg +1 -0
  114. package/img/rehearsal-areas.svg +1 -0
  115. package/img/small/hero-man.png +0 -0
  116. package/img/small/mother-and-daughter-in-ireland.jpg +0 -0
  117. package/img/small/mum-and-child-healthcare-belfast.jpg +0 -0
  118. package/img/small/placeholder-card.png +0 -0
  119. package/img/small/placeholder-news-medium.png +0 -0
  120. package/img/small/placeholder-news.png +0 -0
  121. package/img/small/placeholder-portrait.png +0 -0
  122. package/img/small/students.jpg +0 -0
  123. package/img/small/woman-in-purple-dress-shirt.jpg +0 -0
  124. package/package.json +4 -4
  125. package/scripts/main.es5.js +7 -0
  126. package/scripts/main.js +7 -0
  127. package/scss/base/_fonts.scss +4 -0
  128. package/scss/base/_forms.scss +29 -0
  129. package/scss/base/_global.scss +65 -0
  130. package/scss/base/_index.scss +4 -0
  131. package/scss/base/_typography.scss +46 -0
  132. package/scss/census.scss +2 -0
  133. package/scss/error.scss +27 -0
  134. package/scss/helpers/_functions.scss +44 -0
  135. package/scss/helpers/_index.scss +3 -0
  136. package/scss/helpers/_mixins.scss +94 -0
  137. package/scss/helpers/_mq.scss +93 -0
  138. package/scss/main.scss +71 -0
  139. package/scss/objects/_container.scss +34 -0
  140. package/scss/objects/_index.scss +3 -0
  141. package/scss/objects/_page.scss +49 -0
  142. package/scss/objects/_spacing.scss +23 -0
  143. package/scss/overrides/hcm.scss +81 -0
  144. package/scss/overrides/rtl.scss +131 -0
  145. package/scss/patternlib.scss +216 -0
  146. package/scss/print.scss +66 -0
  147. package/scss/settings/_census.scss +13 -0
  148. package/scss/utilities/_border.scss +12 -0
  149. package/scss/utilities/_colors.scss +17 -0
  150. package/scss/utilities/_display.scss +19 -0
  151. package/scss/utilities/_float.scss +34 -0
  152. package/scss/utilities/_grid.scss +245 -0
  153. package/scss/utilities/_index.scss +10 -0
  154. package/scss/utilities/_margin.scss +24 -0
  155. package/scss/utilities/_pad.scss +25 -0
  156. package/scss/utilities/_typography.scss +88 -0
  157. package/scss/utilities/_utilities.scss +31 -0
  158. package/scss/utilities/_visibility.scss +45 -0
  159. package/scss/vars/_colors.scss +112 -0
  160. package/scss/vars/_forms.scss +50 -0
  161. package/scss/vars/_grid.scss +17 -0
  162. package/scss/vars/_index.scss +5 -0
  163. package/scss/vars/_typography.scss +67 -0
  164. package/scss/vars/_vars.scss +1 -0
  165. package/page-templates/_template.njk +0 -242
@@ -0,0 +1,289 @@
1
+ import Modal from '../modal/modal';
2
+
3
+ export default class Timeout {
4
+ constructor(context, url, time) {
5
+ this.context = context;
6
+ this.sessionExpiryEndpoint = url;
7
+ this.initialExpiryTime = time;
8
+ this.continueButton = context.querySelector('.ons-js-modal-btn');
9
+ this.countdown = context.querySelector('.ons-js-timeout-timer');
10
+ this.accessibleCountdown = context.querySelector('.ons-js-timeout-timer-acc');
11
+ this.timeOutRedirectUrl = context.getAttribute('data-redirect-url');
12
+ this.modalVisibleInMilliseconds = context.getAttribute('data-show-modal-time') * 1000;
13
+
14
+ // Language dependent text strings
15
+ this.minutesTextSingular = context.getAttribute('data-minutes-text-singular');
16
+ this.minutesTextPlural = context.getAttribute('data-minutes-text-plural');
17
+ this.secondsTextSingular = context.getAttribute('data-seconds-text-singular');
18
+ this.secondsTextPlural = context.getAttribute('data-seconds-text-plural');
19
+ this.countdownText = context.getAttribute('data-countdown-text');
20
+ this.redirectingText = context.getAttribute('data-redirecting-text');
21
+
22
+ // Settings
23
+ this.expiryTimeInMilliseconds = 0;
24
+ this.expiryTime = '';
25
+ this.showModalTimeout = null;
26
+ this.timers = [];
27
+ this.timerRunOnce = false;
28
+
29
+ // Create modal instance
30
+ this.modal = new Modal(this.context);
31
+
32
+ // Start module
33
+ this.initialise();
34
+ }
35
+
36
+ async initialise() {
37
+ this.expiryTime = await this.setNewExpiryTime();
38
+ this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(this.expiryTime);
39
+
40
+ this.bindEventListeners();
41
+ }
42
+
43
+ bindEventListeners() {
44
+ window.onload = this.startTimeout();
45
+ window.addEventListener('focus', this.handleWindowFocus.bind(this));
46
+ window.addEventListener('keydown', this.escToClose.bind(this));
47
+ this.continueButton.addEventListener('click', this.closeModalAndRestartTimeout.bind(this));
48
+ this.addThrottledEvents();
49
+ }
50
+
51
+ startTimeout() {
52
+ clearTimeout(this.showModalTimeout);
53
+ this.showModalTimeout = setTimeout(this.openModal.bind(this), this.expiryTimeInMilliseconds - this.modalVisibleInMilliseconds);
54
+ }
55
+
56
+ async openModal() {
57
+ const modalWillOpen = await this.hasExpiryTimeResetInAnotherTab();
58
+ if (modalWillOpen && !this.modal.isDialogOpen()) {
59
+ this.modal.openDialog();
60
+ this.startUiCountdown();
61
+ }
62
+ }
63
+
64
+ async startUiCountdown() {
65
+ this.clearTimers();
66
+ clearInterval(this.shouldModalCloseCheck);
67
+
68
+ this.shouldModalCloseCheck = setInterval(async () => {
69
+ await this.hasExpiryTimeResetInAnotherTab();
70
+ }, 20000);
71
+
72
+ let millseconds = this.modalVisibleInMilliseconds;
73
+ let seconds = millseconds / 1000;
74
+ let timers = this.timers;
75
+ let $this = this;
76
+
77
+ (async function runTimer() {
78
+ const minutesLeft = parseInt(seconds / 60, 10);
79
+ const secondsLeft = parseInt(seconds % 60, 10);
80
+ const timerExpired = minutesLeft < 1 && secondsLeft < 1;
81
+
82
+ const minutesText =
83
+ minutesLeft + ' ' + (minutesLeft >= 2 ? $this.minutesTextPlural : minutesLeft === 1 ? $this.minutesTextSingular : '');
84
+ const secondsText =
85
+ secondsLeft + ' ' + (secondsLeft >= 2 ? $this.secondsTextPlural : secondsLeft === 1 ? $this.secondsTextSingular : '');
86
+
87
+ let timeLeftText =
88
+ $this.countdownText +
89
+ ' <span class="ons-u-fw-b">' +
90
+ (minutesLeft > 0 ? minutesText : '') +
91
+ (minutesLeft > 0 && secondsLeft > 0 ? ' ' : '') +
92
+ (secondsLeft > 0 ? secondsText : '') +
93
+ '</span>.';
94
+
95
+ if (timerExpired) {
96
+ const shouldExpire = await $this.hasExpiryTimeResetInAnotherTab();
97
+
98
+ if (shouldExpire) {
99
+ $this.countdown.innerHTML = '<span class="ons-u-fw-b">' + $this.redirectingText + '</span>';
100
+ $this.accessibleCountdown.innerHTML = $this.redirectingText;
101
+ setTimeout($this.redirect.bind($this), 2000);
102
+ }
103
+ } else {
104
+ seconds--;
105
+ $this.expiryTimeInMilliseconds = seconds * 1000;
106
+ $this.countdown.innerHTML = timeLeftText;
107
+
108
+ if (minutesLeft < 1 && secondsLeft < 20) {
109
+ $this.accessibleCountdown.setAttribute('aria-live', 'assertive');
110
+ }
111
+
112
+ if (!$this.timerRunOnce) {
113
+ $this.accessibleCountdown.innerHTML = timeLeftText;
114
+ $this.timerRunOnce = true;
115
+ } else if (secondsLeft % 15 === 0) {
116
+ $this.accessibleCountdown.innerHTML = timeLeftText;
117
+ }
118
+
119
+ timers.push(setTimeout(runTimer.bind($this), 1000));
120
+ }
121
+ })();
122
+ }
123
+
124
+ async hasExpiryTimeResetInAnotherTab() {
125
+ const checkExpiryTime = await this.getExpiryTime();
126
+
127
+ if (checkExpiryTime != this.expiryTime) {
128
+ this.expiryTime = checkExpiryTime;
129
+ this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(checkExpiryTime);
130
+ this.closeModalAndRestartTimeout(this.expiryTimeInMilliseconds);
131
+ } else {
132
+ return true;
133
+ }
134
+ }
135
+
136
+ closeModalAndRestartTimeout(timeInMilliSeconds) {
137
+ if (typeof timeInMilliSeconds !== 'string') {
138
+ timeInMilliSeconds = false;
139
+ }
140
+ if (this.modal.isDialogOpen()) {
141
+ this.modal.closeDialog();
142
+ }
143
+ this.restartTimeout(timeInMilliSeconds);
144
+ }
145
+
146
+ async restartTimeout(timeInMilliSeconds) {
147
+ this.clearTimers();
148
+ clearInterval(this.shouldModalCloseCheck);
149
+
150
+ if (timeInMilliSeconds) {
151
+ this.expiryTimeInMilliseconds = timeInMilliSeconds;
152
+ } else {
153
+ const createNewExpiryTime = await this.setNewExpiryTime();
154
+ this.expiryTime = createNewExpiryTime;
155
+ this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(createNewExpiryTime);
156
+ }
157
+
158
+ this.startTimeout();
159
+ }
160
+
161
+ async handleWindowFocus() {
162
+ if (this.sessionExpiryEndpoint) {
163
+ const canSetNewExpiry = await this.setNewExpiryTime();
164
+ if (!canSetNewExpiry) {
165
+ this.redirect();
166
+ } else {
167
+ this.closeModalAndRestartTimeout();
168
+ }
169
+ }
170
+ }
171
+
172
+ escToClose(event) {
173
+ if (this.modal.isDialogOpen() && event.keyCode === 27) {
174
+ this.closeModalAndRestartTimeout();
175
+ }
176
+ }
177
+
178
+ async setNewExpiryTime() {
179
+ let newExpiryTime;
180
+ if (!this.sessionExpiryEndpoint) {
181
+ // For demo purposes
182
+ const demoTime = new Date(this.initialExpiryTime ? this.initialExpiryTime : Date.now() + 60 * 1000);
183
+ newExpiryTime = new Date(demoTime).toISOString();
184
+ } else {
185
+ newExpiryTime = await this.fetchExpiryTime('PATCH');
186
+ }
187
+ return newExpiryTime;
188
+ }
189
+
190
+ async getExpiryTime() {
191
+ if (this.sessionExpiryEndpoint) {
192
+ const currentExpiryTime = await this.fetchExpiryTime('GET');
193
+ return currentExpiryTime;
194
+ } else {
195
+ // For demo purposes
196
+ return this.expiryTime;
197
+ }
198
+ }
199
+
200
+ async fetchExpiryTime(fetchMethod) {
201
+ let response = await fetch(this.sessionExpiryEndpoint, {
202
+ method: fetchMethod,
203
+ headers: { 'Cache-Control': 'no-cache', 'Content-type': 'application/json; charset=UTF-8' },
204
+ });
205
+ if (!response.ok) {
206
+ this.redirect();
207
+ return false;
208
+ }
209
+
210
+ let json = await response.json();
211
+
212
+ return json.expires_at;
213
+ }
214
+
215
+ convertTimeToMilliSeconds(expiryTime) {
216
+ const time = new Date(expiryTime);
217
+ const calculateTimeInMilliSeconds = Math.abs(time - new Date());
218
+
219
+ return calculateTimeInMilliSeconds;
220
+ }
221
+
222
+ redirect() {
223
+ window.location.replace(this.timeOutRedirectUrl);
224
+ }
225
+
226
+ clearTimers() {
227
+ for (let i = 0; i < this.timers.length; i++) {
228
+ clearTimeout(this.timers[i]);
229
+ }
230
+ }
231
+
232
+ addThrottledEvents() {
233
+ window.onclick = this.throttle(() => {
234
+ /* istanbul ignore next */
235
+ if (!this.modal.isDialogOpen()) {
236
+ this.restartTimeout();
237
+ }
238
+ }, 61000);
239
+
240
+ window.onmousemove = this.throttle(() => {
241
+ /* istanbul ignore next */
242
+ if (!this.modal.isDialogOpen()) {
243
+ this.restartTimeout();
244
+ }
245
+ }, 61000);
246
+
247
+ window.onmousedown = this.throttle(() => {
248
+ /* istanbul ignore next */
249
+ if (!this.modal.isDialogOpen()) {
250
+ this.restartTimeout();
251
+ }
252
+ }, 61000);
253
+
254
+ window.onscroll = this.throttle(() => {
255
+ /* istanbul ignore next */
256
+ if (!this.modal.isDialogOpen()) {
257
+ this.restartTimeout();
258
+ }
259
+ }, 61000);
260
+
261
+ window.onkeypress = this.throttle(() => {
262
+ /* istanbul ignore next */
263
+ if (!this.modal.isDialogOpen()) {
264
+ this.restartTimeout();
265
+ }
266
+ }, 61000);
267
+
268
+ window.onkeyup = this.throttle(() => {
269
+ /* istanbul ignore next */
270
+ if (!this.modal.isDialogOpen()) {
271
+ this.restartTimeout();
272
+ }
273
+ }, 61000);
274
+ }
275
+
276
+ throttle(func, wait) {
277
+ let waiting = false;
278
+ return function() {
279
+ if (waiting) {
280
+ return;
281
+ }
282
+ waiting = true;
283
+ setTimeout(async () => {
284
+ func.apply(this, arguments);
285
+ waiting = false;
286
+ }, wait);
287
+ };
288
+ }
289
+ }