govuk_publishing_components 43.4.0 → 43.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/views/govuk_publishing_components/components/_radio.html.erb +2 -0
  3. data/app/views/govuk_publishing_components/components/docs/inverse_header.yml +2 -30
  4. data/app/views/govuk_publishing_components/components/docs/radio.yml +15 -0
  5. data/lib/govuk_publishing_components/version.rb +1 -1
  6. data/node_modules/accessible-autocomplete/CHANGELOG.md +398 -0
  7. data/node_modules/accessible-autocomplete/CODEOWNERS +2 -0
  8. data/node_modules/accessible-autocomplete/CONTRIBUTING.md +161 -0
  9. data/node_modules/accessible-autocomplete/LICENSE.txt +20 -0
  10. data/node_modules/accessible-autocomplete/Procfile +1 -0
  11. data/node_modules/accessible-autocomplete/README.md +490 -0
  12. data/node_modules/accessible-autocomplete/accessibility-criteria.md +43 -0
  13. data/node_modules/accessible-autocomplete/app.json +15 -0
  14. data/node_modules/accessible-autocomplete/babel.config.js +29 -0
  15. data/node_modules/accessible-autocomplete/dist/accessible-autocomplete.min.css +3 -0
  16. data/node_modules/accessible-autocomplete/dist/accessible-autocomplete.min.css.map +1 -0
  17. data/node_modules/accessible-autocomplete/dist/accessible-autocomplete.min.js +2 -0
  18. data/node_modules/accessible-autocomplete/dist/accessible-autocomplete.min.js.map +1 -0
  19. data/node_modules/accessible-autocomplete/dist/lib/accessible-autocomplete.preact.min.js +2 -0
  20. data/node_modules/accessible-autocomplete/dist/lib/accessible-autocomplete.preact.min.js.map +1 -0
  21. data/node_modules/accessible-autocomplete/dist/lib/accessible-autocomplete.react.min.js +2 -0
  22. data/node_modules/accessible-autocomplete/dist/lib/accessible-autocomplete.react.min.js.map +1 -0
  23. data/node_modules/accessible-autocomplete/examples/ajax-source.html +300 -0
  24. data/node_modules/accessible-autocomplete/examples/form-single.html +381 -0
  25. data/node_modules/accessible-autocomplete/examples/form.html +673 -0
  26. data/node_modules/accessible-autocomplete/examples/index.html +693 -0
  27. data/node_modules/accessible-autocomplete/examples/preact/index.html +346 -0
  28. data/node_modules/accessible-autocomplete/examples/react/index.html +347 -0
  29. data/node_modules/accessible-autocomplete/examples/suggestions.json +258 -0
  30. data/node_modules/accessible-autocomplete/package.json +93 -0
  31. data/node_modules/accessible-autocomplete/postcss.config.js +16 -0
  32. data/node_modules/accessible-autocomplete/preact.js +1 -0
  33. data/node_modules/accessible-autocomplete/react.js +1 -0
  34. data/node_modules/accessible-autocomplete/scripts/check-staged.mjs +16 -0
  35. data/node_modules/accessible-autocomplete/src/autocomplete.css +167 -0
  36. data/node_modules/accessible-autocomplete/src/autocomplete.js +610 -0
  37. data/node_modules/accessible-autocomplete/src/dropdown-arrow-down.js +11 -0
  38. data/node_modules/accessible-autocomplete/src/status.js +125 -0
  39. data/node_modules/accessible-autocomplete/src/wrapper.js +60 -0
  40. data/node_modules/accessible-autocomplete/test/functional/dropdown-arrow-down.js +46 -0
  41. data/node_modules/accessible-autocomplete/test/functional/index.js +809 -0
  42. data/node_modules/accessible-autocomplete/test/functional/wrapper.js +339 -0
  43. data/node_modules/accessible-autocomplete/test/integration/index.js +309 -0
  44. data/node_modules/accessible-autocomplete/test/karma.config.js +46 -0
  45. data/node_modules/accessible-autocomplete/test/wdio.config.js +123 -0
  46. data/node_modules/accessible-autocomplete/webpack.config.mjs +244 -0
  47. metadata +57 -2
@@ -0,0 +1,300 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Accessible Autocomplete AJAX source example</title>
7
+ <style>
8
+ /* Example page specific styling. */
9
+ html {
10
+ color: #111;
11
+ background: #FFF;
12
+ font-family: -apple-system, BlinkMacSystemFont, 'avenir next', avenir, 'helvetica neue', helvetica, ubuntu, roboto, noto, 'segoe ui', arial, sans-serif;
13
+ font-size: 16px;
14
+ line-height: 1.5;
15
+ }
16
+
17
+ body {
18
+ padding-left: 1rem;
19
+ padding-right: 1rem;
20
+ }
21
+
22
+ h1, h2, h3, h4, h5, h6 {
23
+ line-height: normal;
24
+ }
25
+
26
+ label {
27
+ display: block;
28
+ margin-bottom: .5rem;
29
+ }
30
+
31
+ code {
32
+ padding-left: .5em;
33
+ padding-right: .5em;
34
+ background: #EFEFEF;
35
+ font-weight: normal;
36
+ font-family: monospace;
37
+ }
38
+
39
+ main {
40
+ max-width: 40em;
41
+ margin-left: auto;
42
+ margin-right: auto;
43
+ }
44
+
45
+ .autocomplete-wrapper {
46
+ max-width: 20em;
47
+ margin-bottom: 4rem;
48
+ }
49
+
50
+ .submitted--hidden {
51
+ display: none;
52
+ }
53
+ </style>
54
+ <link rel="stylesheet" href="../dist/accessible-autocomplete.min.css">
55
+ </head>
56
+ <body>
57
+ <main>
58
+ <h1>Accessible Autocomplete AJAX source example</h1>
59
+
60
+ <div class="submitted submitted--hidden">
61
+ <p>You submitted:</p>
62
+ <ul>
63
+ <li><code>"last-location": <span class="submitted__last-location"></span></code></li>
64
+ </ul>
65
+ <hr />
66
+ </div>
67
+
68
+ <form action="form-single.html" method="get">
69
+ <label for="last-location">What was the last location you visited?</label>
70
+ <div class="autocomplete-wrapper">
71
+ </div>
72
+
73
+ <button type="submit">Submit your answer</button>
74
+ </form>
75
+ </main>
76
+
77
+ <script type="text/javascript" src="../dist/accessible-autocomplete.min.js"></script>
78
+ <script type="text/javascript">
79
+ // Sending requests to a server means that when the autocomplete has no
80
+ // result it may not be because there are no results, but because these
81
+ // results are being fetched, or because an error happened. We can use the
82
+ // function for internationalising the 'No results found' message to
83
+ // provide a little more context to users.
84
+ //
85
+ // It'll rely on a `status` variable updated by the wrappers of the
86
+ // function making the request (see thereafter)
87
+ let status;
88
+ function tNoResults() {
89
+ if (status === 'loading') {
90
+ return 'Loading suggestions...'
91
+ } else if (status === 'error') {
92
+ return 'Sorry, an error occurred'
93
+ }else {
94
+ return 'No results found'
95
+ }
96
+ }
97
+
98
+ // The aim being to load suggestions from a server, we'll need a function
99
+ // that does just that. This one uses `fetch`, but you could also use
100
+ // XMLHttpRequest or whichever library is the most suitable to your
101
+ // project
102
+ //
103
+ // For lack of a actual server able of doing computation our endpoint will
104
+ // return the whole list of countries and we'll simulate the work of the
105
+ // server client-side
106
+ function requestSuggestions(query, fetchArgs = {}) {
107
+ return fetch('./suggestions.json', fetchArgs)
108
+ .then((response) => response.json())
109
+ }
110
+
111
+ // We'll wrap that function multiple times, each enhancing the previous
112
+ // wrapping to handle the the different behaviours necessary to
113
+ // appropriately coordinate requests to the server and display feedback to
114
+ // users
115
+ const makeRequest =
116
+ // Wrapping everything is the error handling to make sure it catches
117
+ // errors from any of the other wrappers
118
+ trackErrors(
119
+ // Next up is tracking whether we're loading new results
120
+ trackLoading(
121
+ // To avoid overloading the server with potentially costly requests
122
+ // as well as avoid wasting bandwidth while users are typing we'll
123
+ // only send requests a little bit after they stop typing
124
+ debounce(
125
+ // Finally we want to cancel requests that are already sent, so
126
+ // only the results of the last one update the UI This is the role
127
+ // of the next two wrappers
128
+ abortExisting(
129
+ // That last one is for demo only, to simulate server behaviours
130
+ // (latency, errors, filtering) on the client
131
+ simulateServer(
132
+ requestSuggestions
133
+ )
134
+ ),
135
+ 250
136
+ )
137
+ )
138
+ );
139
+
140
+ // We can then use the function we built and adapt it to the autocomplete
141
+ // API encapsulating the adjustments specific to rendering the 'No result
142
+ // found' message
143
+ function source(query, populateResults) {
144
+ // Start by clearing the results to ensure a loading message
145
+ // shows when a the query gets updated after results have loaded
146
+ populateResults([])
147
+
148
+ makeRequest(query)
149
+ // Only update the results if an actual array of options get returned
150
+ // allowing for `makeRequest` to avoid making updates to results being
151
+ // already displayed by resolving to `undefined`, like when we're
152
+ // aborting requests
153
+ .then(options => options && populateResults(options))
154
+ // In case of errors, we need to clear the results so the accessible
155
+ // autocomplate show its 'No result found'
156
+ .catch(error => populateResults([]))
157
+ }
158
+
159
+ // And finally we can set up our accessible autocomplete
160
+ const element = document.querySelector('.autocomplete-wrapper')
161
+ const id = 'autocomplete-default'
162
+ accessibleAutocomplete({
163
+ element: element,
164
+ id: id,
165
+ source: source,
166
+ tNoResults: tNoResults,
167
+ menuAttributes: {
168
+ "aria-labelledby": id
169
+ },
170
+ inputClasses: "govuk-input"
171
+ })
172
+
173
+ ////
174
+ // INTERNAL DETAILS
175
+ ////
176
+
177
+ // Technically, it'd be the server doing the filtering but for lack of
178
+ // server, we're requesting the whole list and filter client-side.
179
+ // Similarly, we'll use a specific query to trigger error for demo
180
+ // purpose, which will be easier than going in the devtools and making the
181
+ // request error We'll also simulate that the server takes a little time
182
+ // to respond to make things more visible in the UI
183
+ const SERVER_LATENCY = 2500;
184
+ function simulateServer(fn) {
185
+ return function(query, ...args) {
186
+ return new Promise(resolve => {
187
+ setTimeout(() => {
188
+ const suggestions = fn(query, ...args)
189
+ .then((response) => {
190
+ if (query === 'trigger-error') {
191
+ throw new Error('Custom error')
192
+ }
193
+ return response;
194
+ })
195
+ .then(countries => {
196
+ return countries.filter(country => country.toLowerCase().indexOf(query.toLowerCase()) !== -1)
197
+ })
198
+
199
+ resolve(suggestions)
200
+ }, SERVER_LATENCY)
201
+ })
202
+ }
203
+ }
204
+
205
+ // Debouncing limits the number of requests being sent
206
+ // but does not guarantee the order in which the responses come in
207
+ // Due to network and server latency, a response to an earlier request
208
+ // may come back after a response to a later request
209
+ // This keeps track of the AbortController of the last request sent
210
+ // so it can be cancelled before sending a new one
211
+ //
212
+ // NOTE: If you're using `XMLHttpRequest`s or a custom library,
213
+ // they'll have a different mechanism for aborting. You can either:
214
+ // - adapt this function to store whatever object lets you abort in-flight requests
215
+ // - or adapt your version of `requestSuggestion` to listen to the `signal`
216
+ // that this function passes to the wrapped function and trigger
217
+ // whichever API for aborting you have available
218
+ // See: https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal#events
219
+ let abortController;
220
+ function abortExisting(fn) {
221
+ return function(...args) {
222
+ if (abortController) {
223
+ abortController.abort();
224
+ }
225
+
226
+ abortController = new AbortController();
227
+
228
+ return fn(...args, {signal: abortController.signal})
229
+ .then(result => {
230
+ abortController = null;
231
+ return result;
232
+ }, error => {
233
+ // Aborting requests will lead to `fetch` rejecting with an
234
+ // `AbortError` In that situation, that's something we expect, so
235
+ // we don't want to show a message to users
236
+ if (error.name !== 'AbortError') {
237
+ abortController = null;
238
+ throw error;
239
+ }
240
+ })
241
+ }
242
+ }
243
+
244
+ // Debounces the given function so it only gets executed after a specific delay
245
+ function debounce(fn, wait) {
246
+ let timeout
247
+ return function (...args) {
248
+ return new Promise(resolve => {
249
+ clearTimeout(timeout)
250
+
251
+ const later = function () {
252
+ timeout = null
253
+ resolve(fn(...args))
254
+ }
255
+ timeout = setTimeout(later, wait)
256
+ })
257
+ }
258
+ }
259
+
260
+
261
+ // Tracks the loading state so we can adapt the message being displayed to the user
262
+ function trackLoading(fn) {
263
+ return function(...args) {
264
+ status = 'loading';
265
+ return fn(...args)
266
+ .then(result => {
267
+ status = null;
268
+ return result
269
+ }, error => {
270
+ status = null;
271
+ throw error
272
+ })
273
+ }
274
+ }
275
+
276
+ // In a similar fashion, we can track errors happening, which will adjust the message
277
+ function trackErrors(fn) {
278
+ return function(...args) {
279
+ return fn(...args)
280
+ .catch(error => {
281
+ status = 'error'
282
+ throw error
283
+ })
284
+ }
285
+ }
286
+ </script>
287
+
288
+ <script>
289
+ var queryStringParameters = window.location.search
290
+ var previouslySubmitted = queryStringParameters.length > 0
291
+ if (previouslySubmitted) {
292
+ var submittedEl = document.querySelector('.submitted')
293
+ submittedEl.classList.remove('submitted--hidden')
294
+ var params = new URLSearchParams(document.location.search.split('?')[1])
295
+ document.querySelector('.submitted__last-location').innerHTML = params.get('last-location')
296
+ document.querySelector('.submitted__passport-location').innerHTML = params.get('passport-location')
297
+ }
298
+ </script>
299
+ </body>
300
+ </html>