@ministryofjustice/hmpps-connect-dps-shared-items 4.4.0 → 5.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.
package/README.md CHANGED
@@ -27,7 +27,7 @@ npm install @ministryofjustice/hmpps-connect-dps-shared-items
27
27
  Add the `hmpps-connect-dps-shared-items` assets directory to nunjucks configuration in your application:
28
28
 
29
29
  ```javascript
30
- const njkEnv = nunjucks.configure(
30
+ const njkEnv = nunjucks.configure(
31
31
  [
32
32
  path.join(__dirname, '../../server/views'),
33
33
  ...,
@@ -48,11 +48,11 @@ then import the component into your nunjucks file:
48
48
  ### Styling
49
49
  Include the package scss within the `index.scss` file. You can either import all:
50
50
  ```scss
51
- @import 'node_modules/@ministryofjustice/hmpps-connect-dps-shared-items/dist/assets/scss/all';
51
+ @import 'node_modules/@ministryofjustice/hmpps-connect-dps-shared-items/dist/assets/scss/all';
52
52
  ```
53
53
  or import the specific component scss you are using, e.g:
54
54
  ```scss
55
- @import 'node_modules/@ministryofjustice/hmpps-connect-dps-shared-items/dist/assets/dps/components/alert-flag/alert-flag';
55
+ @import 'node_modules/@ministryofjustice/hmpps-connect-dps-shared-items/dist/assets/dps/components/alert-flag/alert-flag';
56
56
  ```
57
57
 
58
58
  ### Client side javascript
@@ -66,10 +66,12 @@ connectDps.initAll()
66
66
 
67
67
  ## Library Components:
68
68
 
69
- 1. [Alert Flag](readme/components/alertFlag/alert-flag.md)
70
- 2. [Address Autosuggest](readme/components/addressAutosuggest/address-autosuggest.md)
71
- 3. [Webcam Upload](readme/components/webcamCapture/webcam-capture.md)
69
+ 1. [Address Autosuggest](readme/components/addressAutosuggest/address-autosuggest.md)
70
+ 2. [Alert Flag](readme/components/alertFlag/alert-flag.md)
71
+ 3. [Modal](readme/components/modal/modal.md)
72
+ 4. [Webcam Upload](readme/components/webcamCapture/webcam-capture.md)
72
73
 
73
74
  ## For Library Developers
74
75
 
75
76
  1. [Publishing to NPM](readme/publishing.md)
77
+ 2. To preview all components locally, run `npm run build` and then `npm start`
@@ -1,5 +1,4 @@
1
- @import 'govuk-frontend/dist/govuk/helpers/colour';
2
- @import 'govuk-frontend/dist/govuk/settings/colours-applied';
1
+ @use "govuk-frontend/dist/govuk/helpers/colour";
3
2
 
4
3
  .hmpps-address-autosuggest {
5
4
  position: relative;
@@ -15,7 +14,7 @@
15
14
  }
16
15
 
17
16
  &__results {
18
- border: 1px solid $govuk-border-colour;
17
+ border: 1px solid colour.govuk-functional-colour(border);
19
18
  border-radius: 3px;
20
19
  display: none;
21
20
  margin: 0 0 0;
@@ -25,13 +24,13 @@
25
24
  }
26
25
 
27
26
  &__results-title {
28
- background: govuk-colour("light-grey");
29
- border-bottom: 1px solid $govuk-border-colour;
27
+ background: colour.govuk-colour("black", $variant: "tint-95");
28
+ border-bottom: 1px solid colour.govuk-functional-colour(border);
30
29
  padding: 0.25rem 0.5rem;
31
30
  }
32
31
 
33
32
  &__listbox {
34
- background: govuk-colour("white");
33
+ background: colour.govuk-colour("white");
35
34
  list-style: none;
36
35
  margin: 0;
37
36
  padding: 0;
@@ -47,22 +46,22 @@
47
46
  padding: 0.25rem 0.5rem;
48
47
 
49
48
  &:not(:last-child) {
50
- border-bottom: 1px solid $govuk-border-colour;
49
+ border-bottom: 1px solid colour.govuk-functional-colour(border);
51
50
  }
52
51
 
53
52
  &--focused:not(&--no-results) {
54
53
  background: #1d70b8;
55
54
  border-color: #1d70b8;
56
- color: govuk-colour("white");
55
+ color: colour.govuk-colour("white");
57
56
  }
58
57
 
59
58
  &:active:not(&--no-results) {
60
59
  background: var(--ons-color-focus);
61
- color: govuk-colour("black");
60
+ color: colour.govuk-colour("black");
62
61
  }
63
62
 
64
63
  &--no-results {
65
- background: govuk-colour("light-grey");
64
+ background: colour.govuk-colour("black", $variant: "tint-95");
66
65
  cursor: not-allowed;
67
66
  padding: 0.25rem 0.5rem;
68
67
  }
@@ -1,51 +1,45 @@
1
1
  // Based on ONSDigital's https://github.com/ONSdigital/design-system/blob/main/src/js/abortable-fetch.js
2
-
3
- export const FetchStatus = {
4
- unsent: 'UNSENT',
5
- loading: 'LOADING',
6
- done: 'DONE',
7
- }
8
-
9
- export const abortError = 'AbortError'
10
- export const abortTimeout = 'AbortTimeout'
11
-
2
+ const FetchStatus = {
3
+ unsent: 'UNSENT',
4
+ loading: 'LOADING',
5
+ done: 'DONE',
6
+ };
7
+ const abortError = 'AbortError';
8
+ const abortTimeout = 'AbortTimeout';
12
9
  class AbortableFetch {
13
- constructor(url, options) {
14
- this.url = url
15
- this.controller = new window.AbortController()
16
- this.status = FetchStatus.unsent
17
- this.fetchDelay = options?.fetchDelay || 500
18
- }
19
-
20
- async send() {
21
- this.status = FetchStatus.loading
22
- try {
23
- // Abortable delay before querying the API to limit the rate of requests when someone is typing:
24
- await new Promise((resolve) => {
25
- setTimeout(resolve, this.fetchDelay)
26
- this.controller.signal.addEventListener('abort', () => { resolve() }, { once: true })
27
- })
28
-
29
- setTimeout(() => {
30
- this.controller.abort(abortTimeout)
31
- }, 5000)
32
-
33
- const response = await window.fetch(this.url, { signal: this.controller.signal })
34
-
35
- if (!(+response.status === 200)) {
36
- const error = new Error(`API error: ${response?.status ?? 500}`)
37
- error.response = response
38
- throw error
39
- }
40
- return response
41
- } finally {
42
- this.status = FetchStatus.done
10
+ constructor(url, options) {
11
+ this.url = url;
12
+ this.controller = new window.AbortController();
13
+ this.status = FetchStatus.unsent;
14
+ this.fetchDelay = options?.fetchDelay || 500;
15
+ }
16
+ async send() {
17
+ this.status = FetchStatus.loading;
18
+ try {
19
+ // Abortable delay before querying the API to limit the rate of requests when someone is typing:
20
+ await new Promise((resolve) => {
21
+ setTimeout(resolve, this.fetchDelay);
22
+ this.controller.signal.addEventListener('abort', () => { resolve(); }, { once: true });
23
+ });
24
+ setTimeout(() => {
25
+ this.controller.abort(abortTimeout);
26
+ }, 5000);
27
+ const response = await window.fetch(this.url, { signal: this.controller.signal });
28
+ if (!(+response.status === 200)) {
29
+ const error = new Error(`API error: ${response?.status ?? 500}`);
30
+ error.response = response;
31
+ throw error;
32
+ }
33
+ return response;
34
+ }
35
+ finally {
36
+ this.status = FetchStatus.done;
37
+ }
38
+ }
39
+ abort() {
40
+ this.controller.abort();
43
41
  }
44
- }
45
-
46
- abort() {
47
- this.controller.abort()
48
- }
49
42
  }
43
+ const abortableFetch = (url, options) => new AbortableFetch(url, options);
50
44
 
51
- export const abortableFetch = (url, options) => new AbortableFetch(url, options)
45
+ export { FetchStatus, abortError, abortTimeout, abortableFetch };
@@ -1,91 +1,80 @@
1
- // Based on ONSDigital's https://github.com/ONSdigital/design-system/blob/main/src/components/address-input/autosuggest.address.js
2
- import { AutosuggestUi, NoResults } from './autosuggest-ui'
3
- import { abortableFetch, abortError, FetchStatus } from './abortable-fetch'
4
-
5
- const classUPRN = 'hmpps-js-uprn'
6
- const classInputContainer = 'hmpps-address-autosuggest'
7
- const classInput = 'hmpps-js-autosuggest-input'
8
-
9
- export class AutosuggestAddress {
10
- constructor(context) {
11
- this.context = context
12
- this.input = context.querySelector(`.${classInput}`)
13
- this.container = context.querySelector(`.${classInputContainer}`)
14
- this.uprn = context.querySelector(`.${classUPRN}`)
15
- this.findUrl = this.container.getAttribute('data-find-url')
16
- this.fetchDelay = this.container.getAttribute('data-fetch-delay')
17
-
18
- // State:
19
- this.fetch = null
20
-
21
- // Initialise autosuggest:
22
- this.autosuggest = new AutosuggestUi({
23
- context: this.container,
24
- onSelect: this.onAddressSelect.bind(this),
25
- suggestionFunction: this.suggestAddresses.bind(this),
26
- })
27
-
28
- // Check API status:
29
- this.checkAPIStatus()
30
- }
1
+ import { AutosuggestUi, NoResults } from './autosuggest-ui.js';
2
+ import { abortableFetch, abortError, FetchStatus } from './abortable-fetch.js';
31
3
 
32
- async checkAPIStatus() {
33
- this.fetch = abortableFetch(`${this.findUrl}/SW1H9AJ`, { fetchDelay: this.fetchDelay })
34
-
35
- try {
36
- const response = await this.fetch.send()
37
- const status = response && (await response.json()).status
38
- if (status !== 200) {
39
- this.autosuggest.handleNoResults(NoResults.server_error)
40
- }
41
- } catch (error) {
42
- if (error.name !== abortError) {
43
- this.autosuggest.handleNoResults(NoResults.server_error)
44
- }
4
+ // Based on ONSDigital's https://github.com/ONSdigital/design-system/blob/main/src/components/address-input/autosuggest.address.js
5
+ const classUPRN = 'hmpps-js-uprn';
6
+ const classInputContainer = 'hmpps-address-autosuggest';
7
+ const classInput = 'hmpps-js-autosuggest-input';
8
+ class AutosuggestAddress {
9
+ constructor(context) {
10
+ this.context = context;
11
+ this.input = context.querySelector(`.${classInput}`);
12
+ this.container = context.querySelector(`.${classInputContainer}`);
13
+ this.uprn = context.querySelector(`.${classUPRN}`);
14
+ this.findUrl = this.container.getAttribute('data-find-url');
15
+ this.fetchDelay = this.container.getAttribute('data-fetch-delay');
16
+ // State:
17
+ this.fetch = null;
18
+ // Initialise autosuggest:
19
+ this.autosuggest = new AutosuggestUi({
20
+ context: this.container,
21
+ onSelect: this.onAddressSelect.bind(this),
22
+ suggestionFunction: this.suggestAddresses.bind(this),
23
+ });
24
+ // Check API status:
25
+ this.checkAPIStatus();
45
26
  }
46
- }
47
-
48
- async suggestAddresses(query) {
49
- if (this.fetch && this.fetch.status !== FetchStatus.done) {
50
- this.fetch.abort()
27
+ async checkAPIStatus() {
28
+ this.fetch = abortableFetch(`${this.findUrl}/SW1H9AJ`, { fetchDelay: this.fetchDelay });
29
+ try {
30
+ const response = await this.fetch.send();
31
+ const status = response && (await response.json()).status;
32
+ if (status !== 200) {
33
+ this.autosuggest.handleNoResults(NoResults.server_error);
34
+ }
35
+ }
36
+ catch (error) {
37
+ if (error.name !== abortError) {
38
+ this.autosuggest.handleNoResults(NoResults.server_error);
39
+ }
40
+ }
51
41
  }
52
-
53
- // Reset any previously selected result:
54
- this.uprn.value = ''
55
-
56
- return await this.findAddress(query?.replace(/[^A-Z0-9-.' ]/gi, ''))
57
- }
58
-
59
- async findAddress(query) {
60
- this.fetch = abortableFetch(`${this.findUrl}/${query}`, { fetchDelay: this.fetchDelay })
61
- const data = await this.fetch.send()
62
- const response = await data.json()
63
- const status = response.status
64
- const addresses = response.results
65
- return this.mapFindResults(addresses, status)
66
- }
67
-
68
- mapFindResults(results, status) {
69
- if (!results) return { status }
70
-
71
- return {
72
- results: this.addressMapping(results),
73
- status: status,
42
+ async suggestAddresses(query) {
43
+ if (this.fetch && this.fetch.status !== FetchStatus.done) {
44
+ this.fetch.abort();
45
+ }
46
+ // Reset any previously selected result:
47
+ this.uprn.value = '';
48
+ return await this.findAddress(query?.replace(/[^A-Z0-9-.' ]/gi, ''));
74
49
  }
75
- }
76
-
77
- addressMapping(addresses) {
78
- if (!addresses?.length) return []
79
-
80
- return addresses.map(address => ({ uprn: address.uprn, displayText: address.addressString }))
81
- }
82
-
83
- async onAddressSelect(selectedResult) {
84
- if (this.fetch && this.fetch.status !== FetchStatus.done) {
85
- this.fetch.abort()
50
+ async findAddress(query) {
51
+ this.fetch = abortableFetch(`${this.findUrl}/${query}`, { fetchDelay: this.fetchDelay });
52
+ const data = await this.fetch.send();
53
+ const response = await data.json();
54
+ const status = response.status;
55
+ const addresses = response.results;
56
+ return this.mapFindResults(addresses, status);
57
+ }
58
+ mapFindResults(results, status) {
59
+ if (!results)
60
+ return { status };
61
+ return {
62
+ results: this.addressMapping(results),
63
+ status: status,
64
+ };
65
+ }
66
+ addressMapping(addresses) {
67
+ if (!addresses?.length)
68
+ return [];
69
+ return addresses.map(address => ({ uprn: address.uprn, displayText: address.addressString }));
70
+ }
71
+ async onAddressSelect(selectedResult) {
72
+ if (this.fetch && this.fetch.status !== FetchStatus.done) {
73
+ this.fetch.abort();
74
+ }
75
+ this.autosuggest.input.value = selectedResult.displayText;
76
+ this.uprn.value = selectedResult.uprn;
86
77
  }
87
-
88
- this.autosuggest.input.value = selectedResult.displayText
89
- this.uprn.value = selectedResult.uprn
90
- }
91
78
  }
79
+
80
+ export { AutosuggestAddress };