@govuk-one-login/frontend-ui 1.5.0 → 3.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 (37) hide show
  1. package/README.md +42 -0
  2. package/build/all.css +1 -1
  3. package/build/cjs/backend/index.cjs +14 -2
  4. package/build/cjs/backend/index.d.cts +10 -0
  5. package/build/cjs/backend/index.d.ts +10 -0
  6. package/build/cjs/backend/index.d.ts.map +1 -1
  7. package/build/cjs/frontend/index.cjs +225 -268
  8. package/build/cjs/frontend/index.d.cts +2 -1
  9. package/build/cjs/frontend/index.d.ts +2 -1
  10. package/build/cjs/frontend/index.d.ts.map +1 -1
  11. package/build/cjs/frontend/spinner/__tests__/spinner.test.d.ts +0 -4
  12. package/build/cjs/frontend/spinner/__tests__/spinner.test.d.ts.map +1 -1
  13. package/build/cjs/frontend/spinner/spinner.d.ts +54 -84
  14. package/build/cjs/frontend/spinner/spinner.d.ts.map +1 -1
  15. package/build/components/_all.scss +1 -0
  16. package/build/components/bases/identity/identity-base-form.njk +54 -33
  17. package/build/components/bases/identity/identity-base-page.njk +54 -32
  18. package/build/components/bases/ipv-core/ipv-core-base.njk +16 -9
  19. package/build/components/progress-button/_index.scss +44 -0
  20. package/build/components/progress-button/macro.njk +2 -0
  21. package/build/components/progress-button/progress-button.yaml +13 -0
  22. package/build/components/progress-button/template.njk +120 -0
  23. package/build/components/spinner/README.md +70 -52
  24. package/build/components/spinner/_index.scss +2 -11
  25. package/build/components/spinner/template.njk +15 -8
  26. package/build/esm/backend/index.d.ts +10 -0
  27. package/build/esm/backend/index.d.ts.map +1 -1
  28. package/build/esm/backend/index.js +14 -2
  29. package/build/esm/frontend/index.d.ts +2 -1
  30. package/build/esm/frontend/index.d.ts.map +1 -1
  31. package/build/esm/frontend/index.js +226 -269
  32. package/build/esm/frontend/spinner/__tests__/spinner.test.d.ts +0 -4
  33. package/build/esm/frontend/spinner/__tests__/spinner.test.d.ts.map +1 -1
  34. package/build/esm/frontend/spinner/spinner.d.ts +54 -84
  35. package/build/esm/frontend/spinner/spinner.d.ts.map +1 -1
  36. package/package.json +3 -2
  37. package/build/components/spinner/api.njk +0 -27
@@ -1,171 +1,244 @@
1
- function useSpinner() {
2
- const element = document.getElementById("spinner-container");
3
- if (element) {
4
- const spinner = new Spinner(element);
5
- spinner.init();
1
+ async function useSpinner(containerId, pollingFunction, successFunction, errorFunction) {
2
+ const element = document.getElementById(containerId);
3
+ if (element && element instanceof HTMLDivElement) {
4
+ let spinner;
5
+ try {
6
+ spinner = new Spinner(element, pollingFunction, successFunction, errorFunction);
7
+ }
8
+ catch (e) {
9
+ const errorText = document.createElement("p");
10
+ errorText.textContent = "Error configuring spinner: " + e;
11
+ element.replaceChildren(errorText);
12
+ return;
13
+ }
14
+ await spinner.init();
6
15
  }
7
16
  else {
8
- console.warn("Attempting to initiate a spinner on a page with no '#spinner-container' element.");
17
+ console.error(`Attempting to initiate a spinner on a page with no '#${containerId}' div element.`);
9
18
  }
10
19
  }
20
+ var PollResult;
21
+ (function (PollResult) {
22
+ PollResult[PollResult["Success"] = 0] = "Success";
23
+ PollResult[PollResult["Failure"] = 1] = "Failure";
24
+ PollResult[PollResult["Pending"] = 2] = "Pending";
25
+ })(PollResult || (PollResult = {}));
26
+ var SpinnerState;
27
+ (function (SpinnerState) {
28
+ SpinnerState[SpinnerState["Waiting"] = 0] = "Waiting";
29
+ SpinnerState[SpinnerState["LongWaiting"] = 1] = "LongWaiting";
30
+ SpinnerState[SpinnerState["Error"] = 2] = "Error";
31
+ SpinnerState[SpinnerState["Complete"] = 3] = "Complete";
32
+ })(SpinnerState || (SpinnerState = {}));
11
33
  class Spinner {
12
- reflectLongWait() {
13
- if (this.state.spinnerState !== "ready") {
14
- this.state.spinnerStateText = this.content.longWait.spinnerStateText;
34
+ constructor(domContainer, pollingFunction, onSuccess, onError) {
35
+ this.state = SpinnerState.Waiting;
36
+ this.handleAbort = () => {
37
+ this.abortController.abort();
38
+ };
39
+ this.initTimer = (initTime) => {
40
+ this.updateDomTimer = setInterval(() => {
41
+ this.updateStateAccordingToTimeElapsed(initTime);
42
+ this.updateDom();
43
+ }, this.config.msBetweenDomUpdate);
44
+ };
45
+ this.reflectSuccess = () => {
46
+ this.state = SpinnerState.Complete;
47
+ sessionStorage.removeItem("spinnerInitTime");
48
+ };
49
+ this.reflectError = () => {
50
+ this.state = SpinnerState.Error;
51
+ sessionStorage.removeItem("spinnerInitTime");
52
+ this.abortController.abort();
53
+ };
54
+ this.updateStateAccordingToTimeElapsed = (initTime) => {
55
+ const elapsedMilliseconds = Date.now() - initTime;
56
+ if (this.hasCompleted()) {
57
+ // If we've already finished waiting then there's no need to update again.
58
+ return;
59
+ }
60
+ if (elapsedMilliseconds >= this.config.msBeforeAbort) {
61
+ this.reflectError();
62
+ }
63
+ else if (elapsedMilliseconds >= this.config.msBeforeInformingOfLongWait) {
64
+ this.reflectLongWait();
65
+ }
66
+ };
67
+ this.updateDom = () => {
68
+ if (this.hasCompleted()) {
69
+ // We've reached an end state so stop updating the DOM after this
70
+ clearInterval(this.updateDomTimer);
71
+ }
72
+ if (this.displayState === this.state) {
73
+ // No need to update anything
74
+ return;
75
+ }
76
+ this.displayState = this.state;
77
+ const newElementsToDisplay = [];
78
+ switch (this.displayState) {
79
+ case SpinnerState.Waiting:
80
+ newElementsToDisplay.push(this.createSpinnerElement(""));
81
+ this.cloneAndAddIfExists(newElementsToDisplay, this.waitContent);
82
+ break;
83
+ case SpinnerState.LongWaiting:
84
+ newElementsToDisplay.push(this.createSpinnerElement(""));
85
+ this.cloneAndAddIfExists(newElementsToDisplay, this.longWaitContent);
86
+ break;
87
+ case SpinnerState.Complete:
88
+ newElementsToDisplay.push(this.createSpinnerElement("spinner__finished"));
89
+ this.cloneAndAddIfExists(newElementsToDisplay, this.successContent);
90
+ break;
91
+ case SpinnerState.Error:
92
+ if (!this.config.hideSpinnerOnError) {
93
+ newElementsToDisplay.push(this.createSpinnerElement("spinner__finished"));
94
+ }
95
+ this.cloneAndAddIfExists(newElementsToDisplay, this.errorContent);
96
+ break;
97
+ }
98
+ this.visibleElementsContainer.replaceChildren(...newElementsToDisplay);
99
+ if (this.displayState === SpinnerState.Complete) {
100
+ if (this.onSuccess) {
101
+ this.onSuccess();
102
+ }
103
+ this.updateAriaAlert(this.config.ariaAlertCompletionText);
104
+ }
105
+ if (this.displayState === SpinnerState.Error && !!this.onError) {
106
+ this.onError();
107
+ }
108
+ };
109
+ this.container = domContainer;
110
+ this.pollingFunction = pollingFunction;
111
+ if (!pollingFunction) {
112
+ throw new Error("Polling function must be provided");
15
113
  }
114
+ this.onSuccess = onSuccess;
115
+ this.onError = onError;
116
+ this.noJsContent = this.getElementOrThrow("no-js-content");
117
+ this.noJsContent.style.display = "none";
118
+ this.waitContent =
119
+ this.container.querySelector("#wait-content") || undefined;
120
+ this.longWaitContent =
121
+ this.container.querySelector("#long-wait-content") || undefined;
122
+ this.successContent =
123
+ this.container.querySelector("#success-content") || undefined;
124
+ this.errorContent =
125
+ this.container.querySelector("#error-content") || undefined;
126
+ if (!this.successContent && !onSuccess) {
127
+ throw new Error("One of success-content or successFunction must be provided");
128
+ }
129
+ if (!this.errorContent && !onError) {
130
+ throw new Error("One of error-content or errorFunction must be provided");
131
+ }
132
+ this.config = this.getConfig(this.container);
133
+ this.visibleElementsContainer = document.createElement("div");
134
+ this.container.appendChild(this.visibleElementsContainer);
135
+ this.ariaLiveContainer = this.createAriaLiveContainer();
136
+ this.container.appendChild(this.ariaLiveContainer);
137
+ this.abortController = this.createAbortController();
16
138
  }
17
- initialiseState() {
18
- if (this.domRequirementsMet) {
19
- this.state = {
20
- heading: this.content.initial.heading,
21
- spinnerStateText: this.content.initial.spinnerStateText,
22
- spinnerState: this.content.initial.spinnerState,
23
- buttonDisabled: true,
24
- ariaButtonEnabledMessage: "",
25
- done: false,
26
- error: false,
27
- virtualDom: [],
28
- };
139
+ async init() {
140
+ const initTime = this.getInitTime();
141
+ this.updateStateAccordingToTimeElapsed(initTime);
142
+ this.updateDom();
143
+ this.initTimer(initTime);
144
+ await this.callPollingFunction(initTime);
145
+ }
146
+ getElementOrThrow(elementId) {
147
+ const element = this.container.querySelector(`#${elementId}`);
148
+ if (element === null || !(element instanceof HTMLElement)) {
149
+ throw new Error(`HTML Element with id ${elementId} must be provided`);
29
150
  }
151
+ return element;
30
152
  }
31
- initialiseContent(element) {
32
- var _a;
33
- function throwIfMissing(data) {
34
- if (data === undefined || data === null) {
35
- throw new Error("Missing required data");
36
- }
37
- return data;
153
+ getConfig(element) {
154
+ return {
155
+ msBeforeInformingOfLongWait: element.dataset.msBeforeInformingOfLongWait
156
+ ? parseInt(element.dataset.msBeforeInformingOfLongWait)
157
+ : 5000,
158
+ msBeforeAbort: element.dataset.msBeforeAbort
159
+ ? parseInt(element.dataset.msBeforeAbort)
160
+ : 30000,
161
+ msBetweenRequests: element.dataset.msBetweenRequests
162
+ ? parseInt(element.dataset.msBetweenRequests)
163
+ : 2000,
164
+ msBetweenDomUpdate: element.dataset.msBetweenDomUpdate
165
+ ? parseInt(element.dataset.msBetweenDomUpdate)
166
+ : 1000,
167
+ ariaAlertCompletionText: element.dataset.ariaAlertCompletionText
168
+ ? element.dataset.ariaAlertCompletionText
169
+ : undefined,
170
+ hideSpinnerOnError: element.dataset.hideSpinnerOnError
171
+ ? (element.dataset.hideSpinnerOnError === 'true')
172
+ : false,
173
+ };
174
+ }
175
+ createAbortController() {
176
+ const abortController = new AbortController();
177
+ window.removeEventListener("beforeunload", this.handleAbort);
178
+ window.addEventListener("beforeunload", this.handleAbort);
179
+ return abortController;
180
+ }
181
+ getInitTime() {
182
+ const storedSpinnerInitTime = sessionStorage.getItem("spinnerInitTime");
183
+ let spinnerInitTime;
184
+ if (storedSpinnerInitTime === null) {
185
+ spinnerInitTime = Date.now();
186
+ sessionStorage.setItem("spinnerInitTime", spinnerInitTime.toString());
38
187
  }
39
- try {
40
- this.content = {
41
- initial: {
42
- heading: throwIfMissing(element.dataset.initialHeading),
43
- spinnerStateText: throwIfMissing(element.dataset.initialSpinnerstatetext),
44
- spinnerState: throwIfMissing(element.dataset.initialSpinnerstate),
45
- },
46
- error: {
47
- heading: throwIfMissing(element.dataset.errorHeading),
48
- messageText: throwIfMissing(element.dataset.errorMessagetext),
49
- whatYouCanDo: {
50
- heading: throwIfMissing(element.dataset.errorWhatyoucandoHeading),
51
- message: {
52
- text1: throwIfMissing(element.dataset.errorWhatyoucandoMessageText1),
53
- link: {
54
- href: throwIfMissing(element.dataset.errorWhatyoucandoMessageLinkHref),
55
- text: throwIfMissing(element.dataset.errorWhatyoucandoMessageLinkText),
56
- },
57
- text2: throwIfMissing(element.dataset.errorWhatyoucandoMessageText2),
58
- },
59
- },
60
- },
61
- complete: {
62
- spinnerState: throwIfMissing(element.dataset.completeSpinnerstate),
63
- },
64
- longWait: {
65
- spinnerStateText: throwIfMissing(element.dataset.longwaitSpinnerstatetext),
66
- },
67
- continueButton: {
68
- text: (_a = element.dataset.continuebuttonText) !== null && _a !== void 0 ? _a : "Continue",
69
- },
70
- };
71
- this.config = {
72
- apiUrl: element.dataset.apiUrl || this.config.apiUrl,
73
- ariaButtonEnabledMessage: throwIfMissing(element.dataset.ariaButtonEnabledMessage),
74
- msBeforeInformingOfLongWait: element.dataset.msBeforeInformingOfLongWait
75
- ? parseInt(element.dataset.msBeforeInformingOfLongWait)
76
- : this.config.msBeforeInformingOfLongWait,
77
- msBeforeAbort: element.dataset.msBeforeAbort
78
- ? parseInt(element.dataset.msBeforeAbort)
79
- : this.config.msBeforeAbort,
80
- msBetweenRequests: element.dataset.msBetweenRequests
81
- ? parseInt(element.dataset.msBetweenRequests)
82
- : this.config.msBetweenRequests,
83
- msBetweenDomUpdate: element.dataset.msBetweenDomUpdate
84
- ? parseInt(element.dataset.msBetweenDomUpdate)
85
- : this.config.msBetweenDomUpdate,
86
- };
87
- this.domRequirementsMet = true;
188
+ else {
189
+ spinnerInitTime = parseInt(storedSpinnerInitTime, 10);
88
190
  }
89
- catch (e) {
90
- this.domRequirementsMet = false;
191
+ return spinnerInitTime;
192
+ }
193
+ hasCompleted() {
194
+ return (this.state === SpinnerState.Error || this.state === SpinnerState.Complete);
195
+ }
196
+ reflectLongWait() {
197
+ if (!this.hasCompleted()) {
198
+ this.state = SpinnerState.LongWaiting;
91
199
  }
92
200
  }
93
- createVirtualDom() {
94
- const domInitialState = [
95
- {
96
- nodeName: "h1",
97
- text: this.state.heading,
98
- classes: ["govuk-heading-l"],
99
- },
100
- {
101
- nodeName: "div",
102
- id: "spinner",
103
- classes: [
104
- "spinner",
105
- "spinner__pending",
106
- "centre",
107
- this.state.spinnerState,
108
- ],
109
- },
110
- {
111
- nodeName: "p",
112
- text: this.state.spinnerStateText,
113
- classes: ["centre", "spinner-state-text", "govuk-body"],
114
- },
115
- {
116
- nodeName: "button",
117
- text: this.content.continueButton.text,
118
- buttonDisabled: this.state.buttonDisabled,
119
- classes: ["govuk-button", "govuk-!-margin-top-4"],
120
- },
121
- ];
122
- const domErrorState = [
123
- {
124
- nodeName: "h1",
125
- text: this.state.heading,
126
- classes: ["govuk-heading-l"],
127
- },
128
- {
129
- nodeName: "p",
130
- text: this.state.messageText,
131
- classes: ["govuk-body"],
132
- },
133
- {
134
- nodeName: "h2",
135
- text: this.content.error.whatYouCanDo.heading,
136
- classes: ["govuk-heading-m"],
137
- },
138
- {
139
- nodeName: "p",
140
- innerHTML: `${this.content.error.whatYouCanDo.message.text1}<a href="${this.content.error.whatYouCanDo.message.link.href}">${this.content.error.whatYouCanDo.message.link.text}</a>${this.content.error.whatYouCanDo.message.text2}`,
141
- classes: ["govuk-body"],
142
- },
143
- ];
144
- return this.state.error ? domErrorState : domInitialState;
201
+ createSpinnerElement(spinnerStateClass) {
202
+ const spinner = document.createElement("div");
203
+ spinner.id = "spinner";
204
+ spinner.classList.add("spinner", "centre");
205
+ if (spinnerStateClass) {
206
+ spinner.classList.add(spinnerStateClass);
207
+ }
208
+ return spinner;
145
209
  }
146
- async requestIDProcessingStatus(initTime) {
147
- const signal = this.abortController.signal;
148
- await fetch(this.config.apiUrl, { signal })
149
- .then((response) => response.json())
150
- .then((data) => {
151
- if (data.status === "COMPLETED" || data.status === "INTERVENTION") {
152
- this.reflectCompletion();
210
+ cloneAndAddIfExists(list, element) {
211
+ if (element) {
212
+ const cloned = element.cloneNode(true);
213
+ cloned.style.display = "";
214
+ cloned.removeAttribute("id");
215
+ list.push(cloned);
216
+ }
217
+ }
218
+ async callPollingFunction(initTime) {
219
+ if (Date.now() - initTime >= this.config.msBeforeAbort) {
220
+ return;
221
+ }
222
+ await this.pollingFunction(this.abortController.signal)
223
+ .then((response) => {
224
+ if (response === PollResult.Success) {
225
+ this.reflectSuccess();
153
226
  }
154
- else if (data.status === "ERROR") {
227
+ else if (response === PollResult.Failure) {
155
228
  this.reflectError();
156
229
  }
157
- else if (this.notInErrorOrDoneState()) {
230
+ else if (!this.hasCompleted()) {
158
231
  setTimeout(async () => {
159
232
  if (Date.now() - initTime >= this.config.msBeforeAbort) {
160
233
  return;
161
234
  }
162
- await this.requestIDProcessingStatus(initTime);
235
+ await this.callPollingFunction(initTime);
163
236
  }, this.config.msBetweenRequests);
164
237
  }
165
238
  })
166
239
  .catch((error) => {
167
240
  if (error.name !== "AbortError") {
168
- console.error("Error in requestIDProcessingStatus:", error);
241
+ console.error("Error in polling function: ", error);
169
242
  this.reflectError();
170
243
  }
171
244
  })
@@ -173,140 +246,24 @@ class Spinner {
173
246
  this.updateDom();
174
247
  });
175
248
  }
176
- getInitTime() {
177
- const storedSpinnerInitTime = sessionStorage.getItem("spinnerInitTime");
178
- let spinnerInitTime;
179
- if (storedSpinnerInitTime === null) {
180
- spinnerInitTime = Date.now();
181
- sessionStorage.setItem("spinnerInitTime", spinnerInitTime.toString());
182
- }
183
- else {
184
- spinnerInitTime = parseInt(storedSpinnerInitTime, 10);
185
- }
186
- return spinnerInitTime;
187
- }
188
- init() {
189
- if (this.domRequirementsMet) {
190
- const initTime = this.getInitTime();
191
- this.initTimer(initTime);
192
- this.initialiseContainers();
193
- this.updateDom();
194
- this.requestIDProcessingStatus(initTime);
195
- }
249
+ createAriaLiveContainer() {
250
+ // For the Aria alert to work reliably we need to create its container once and then update the contents
251
+ // https://tetralogical.com/blog/2024/05/01/why-are-my-live-regions-not-working/
252
+ const container = document.createElement("div");
253
+ container.setAttribute("aria-live", "assertive");
254
+ container.classList.add("govuk-visually-hidden");
255
+ return container;
196
256
  }
197
- constructor(domContainer) {
198
- this.config = {
199
- apiUrl: "/prove-identity-status",
200
- msBeforeInformingOfLongWait: 5000,
201
- msBeforeAbort: 25000,
202
- msBetweenRequests: 1000,
203
- msBetweenDomUpdate: 2000,
204
- };
205
- this.notInErrorOrDoneState = () => {
206
- return !(this.state.done || this.state.error);
207
- };
208
- this.reflectCompletion = () => {
209
- this.state.spinnerState = "spinner__ready";
210
- this.state.spinnerStateText = this.content.complete.spinnerState;
211
- this.state.buttonDisabled = false;
212
- this.state.ariaButtonEnabledMessage =
213
- this.content.complete.ariaButtonEnabledMessage;
214
- this.state.done = true;
215
- sessionStorage.removeItem("spinnerInitTime");
216
- };
217
- this.reflectError = () => {
218
- this.state.heading = this.content.error.heading;
219
- this.state.messageText = this.content.error.messageText;
220
- this.state.spinnerState = "spinner__failed";
221
- this.state.done = true;
222
- this.state.error = true;
223
- sessionStorage.removeItem("spinnerInitTime");
224
- this.abortController.abort();
225
- };
226
- this.updateAccordingToTimeElapsed = (initTime) => {
227
- const elapsedMilliseconds = Date.now() - initTime;
228
- if (elapsedMilliseconds >= this.config.msBeforeAbort) {
229
- this.reflectError();
230
- }
231
- else if (elapsedMilliseconds >= this.config.msBeforeInformingOfLongWait) {
232
- this.reflectLongWait();
233
- }
234
- };
235
- this.vDomHasChanged = (currentVDom, nextVDom) => {
236
- return JSON.stringify(currentVDom) !== JSON.stringify(nextVDom);
237
- };
238
- this.convert = (node) => {
239
- const el = document.createElement(node.nodeName);
240
- if (node.text)
241
- el.textContent = node.text;
242
- if (node.innerHTML)
243
- el.innerHTML = node.innerHTML;
244
- if (node.id)
245
- el.id = node.id;
246
- if (node.classes)
247
- el.classList.add(...node.classes);
248
- if (node.buttonDisabled)
249
- el.setAttribute("disabled", `${node.buttonDisabled}`);
250
- return el;
251
- };
252
- this.updateAriaAlert = (messageText) => {
257
+ updateAriaAlert(messageText) {
258
+ if (messageText) {
253
259
  while (this.ariaLiveContainer.firstChild) {
254
260
  this.ariaLiveContainer.removeChild(this.ariaLiveContainer.firstChild);
255
261
  }
256
262
  /* Create new message and append it to the live region */
257
263
  const messageNode = document.createTextNode(messageText);
258
264
  this.ariaLiveContainer.appendChild(messageNode);
259
- };
260
- this.updateDom = () => {
261
- const vDomChanged = this.vDomHasChanged(this.state.virtualDom, this.createVirtualDom());
262
- if (vDomChanged) {
263
- document.title = this.state.heading;
264
- this.state.virtualDom = this.createVirtualDom();
265
- const elements = this.state.virtualDom.map(this.convert);
266
- this.spinnerContainer.replaceChildren(...elements);
267
- }
268
- if (this.state.error) {
269
- this.spinnerContainer.classList.add("spinner-container__error");
270
- }
271
- if (this.state.done) {
272
- clearInterval(this.updateDomTimer);
273
- }
274
- if (this.config.ariaButtonEnabledMessage &&
275
- this.state.ariaButtonEnabledMessage !== "") {
276
- this.updateAriaAlert(this.config.ariaButtonEnabledMessage);
277
- }
278
- };
279
- // For the Aria alert to work reliably we need to create its container once and then update the contents
280
- // https://tetralogical.com/blog/2024/05/01/why-are-my-live-regions-not-working/
281
- // So here we create a separate DOM element for the Aria live text that won't be touched when the spinner updates.
282
- this.initialiseContainers = () => {
283
- this.spinnerContainer = document.createElement("div");
284
- this.ariaLiveContainer = document.createElement("div");
285
- this.ariaLiveContainer.setAttribute("aria-live", "assertive");
286
- this.ariaLiveContainer.classList.add("govuk-visually-hidden");
287
- this.ariaLiveContainer.appendChild(document.createTextNode(""));
288
- this.container.replaceChildren(this.spinnerContainer, this.ariaLiveContainer);
289
- };
290
- this.initTimer = (initTime) => {
291
- this.updateAccordingToTimeElapsed(initTime);
292
- this.updateDomTimer = setInterval(() => {
293
- this.updateAccordingToTimeElapsed(initTime);
294
- this.updateDom();
295
- }, this.config.msBetweenDomUpdate);
296
- };
297
- this.handleAbort = () => {
298
- this.abortController.abort();
299
- };
300
- this.initialiseAbortController = () => {
301
- this.abortController = new AbortController();
302
- window.removeEventListener("beforeunload", this.handleAbort);
303
- window.addEventListener("beforeunload", this.handleAbort);
304
- };
305
- this.container = domContainer;
306
- this.initialiseContent(this.container);
307
- this.initialiseState();
308
- this.initialiseAbortController();
265
+ }
309
266
  }
310
267
  }
311
268
 
312
- export { useSpinner };
269
+ export { PollResult, useSpinner };
@@ -1,6 +1,2 @@
1
1
  export declare function wait(ms: number): Promise<unknown>;
2
- export declare function waitUntil(conditionFn: Function, { timeout, interval }?: {
3
- timeout?: number | undefined;
4
- interval?: number | undefined;
5
- }): Promise<void>;
6
2
  //# sourceMappingURL=spinner.test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spinner.test.d.ts","sourceRoot":"","sources":["../../../../../frontend-src/spinner/__tests__/spinner.test.ts"],"names":[],"mappings":"AAEA,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,oBAE9B;AAED,wBAAsB,SAAS,CAC7B,WAAW,EAAE,QAAQ,EACrB,EAAE,OAAc,EAAE,QAAa,EAAE;;;CAAK,iBAcvC"}
1
+ {"version":3,"file":"spinner.test.d.ts","sourceRoot":"","sources":["../../../../../frontend-src/spinner/__tests__/spinner.test.ts"],"names":[],"mappings":"AAGA,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,oBAE9B"}