@cedx/base 0.13.1 → 0.14.1
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 +1 -1
- package/lib/FileExtensions.d.ts.map +1 -1
- package/lib/FileExtensions.js +1 -2
- package/lib/UI/Components/BackButton.d.ts +26 -0
- package/lib/UI/Components/BackButton.d.ts.map +1 -0
- package/lib/UI/Components/BackButton.js +28 -0
- package/lib/UI/Components/LoadingIndicator.js +1 -1
- package/lib/UI/Components/Toast.d.ts +5 -1
- package/lib/UI/Components/Toast.d.ts.map +1 -1
- package/lib/UI/Components/Toast.js +17 -16
- package/lib/UI/Components/Toaster.d.ts +115 -0
- package/lib/UI/Components/Toaster.d.ts.map +1 -0
- package/lib/UI/Components/Toaster.js +147 -0
- package/package.json +1 -1
- package/src/Client/FileExtensions.ts +1 -3
- package/src/Client/UI/Components/BackButton.ts +44 -0
- package/src/Client/UI/Components/LoadingIndicator.ts +1 -1
- package/src/Client/UI/Components/Toast.ts +30 -21
- package/src/Client/UI/Components/Toaster.ts +218 -0
package/ReadMe.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Belin.io Base
|
|
2
|
-
   
|
|
3
3
|
|
|
4
4
|
Base library by [Cédric Belin](https://belin.io), full stack developer,
|
|
5
5
|
implemented in [C#](https://learn.microsoft.com/en-us/dotnet/csharp) and [TypeScript](https://www.typescriptlang.org).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileExtensions.d.ts","sourceRoot":"","sources":["../src/Client/FileExtensions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FileExtensions.d.ts","sourceRoot":"","sources":["../src/Client/FileExtensions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAUzC;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAM,GAAG,IAAI,CAkBvE;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAatC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAOlD"}
|
package/lib/FileExtensions.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Duration } from "./Duration.js";
|
|
2
1
|
/**
|
|
3
2
|
* Downloads the specified file.
|
|
4
3
|
* @param file The file to be downloaded.
|
|
@@ -34,7 +33,7 @@ export function open(file, options = {}) {
|
|
|
34
33
|
return;
|
|
35
34
|
clearInterval(timer);
|
|
36
35
|
URL.revokeObjectURL(url);
|
|
37
|
-
},
|
|
36
|
+
}, 5_000);
|
|
38
37
|
}
|
|
39
38
|
/**
|
|
40
39
|
* Prints the specified file.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component that moves back one page in the session history when clicked.
|
|
3
|
+
*/
|
|
4
|
+
export declare class BackButton extends HTMLElement {
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new back button.
|
|
7
|
+
*/
|
|
8
|
+
constructor();
|
|
9
|
+
/**
|
|
10
|
+
* The number of pages to go back.
|
|
11
|
+
*/
|
|
12
|
+
get steps(): number;
|
|
13
|
+
set steps(value: number);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Declaration merging.
|
|
17
|
+
*/
|
|
18
|
+
declare global {
|
|
19
|
+
/**
|
|
20
|
+
* The map of HTML tag names.
|
|
21
|
+
*/
|
|
22
|
+
interface HTMLElementTagNameMap {
|
|
23
|
+
"back-button": BackButton;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=BackButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackButton.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/BackButton.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAW,SAAQ,WAAW;IAE1C;;OAEG;;IAaH;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;CACD;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,aAAa,EAAE,UAAU,CAAC;KAC1B;CACD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component that moves back one page in the session history when clicked.
|
|
3
|
+
*/
|
|
4
|
+
export class BackButton extends HTMLElement {
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new back button.
|
|
7
|
+
*/
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.addEventListener("click", () => history.go(-this.steps));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Registers the component.
|
|
14
|
+
*/
|
|
15
|
+
static {
|
|
16
|
+
customElements.define("back-button", this);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The number of pages to go back.
|
|
20
|
+
*/
|
|
21
|
+
get steps() {
|
|
22
|
+
const value = Number(this.getAttribute("steps"));
|
|
23
|
+
return Math.max(0, Number.isNaN(value) ? 1 : value);
|
|
24
|
+
}
|
|
25
|
+
set steps(value) {
|
|
26
|
+
this.setAttribute("steps", value.toString());
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -25,7 +25,7 @@ export class LoadingIndicator extends HTMLElement {
|
|
|
25
25
|
*/
|
|
26
26
|
stop(options = {}) {
|
|
27
27
|
this.#requestCount--;
|
|
28
|
-
if (
|
|
28
|
+
if (this.#requestCount <= 0 || options.force) {
|
|
29
29
|
this.#requestCount = 0;
|
|
30
30
|
this.hidden = true;
|
|
31
31
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context } from "
|
|
1
|
+
import { Context } from "../Context.js";
|
|
2
2
|
/**
|
|
3
3
|
* Represents a notification.
|
|
4
4
|
*/
|
|
@@ -23,6 +23,10 @@ export declare class Toast extends HTMLElement {
|
|
|
23
23
|
*/
|
|
24
24
|
get caption(): string;
|
|
25
25
|
set caption(value: string);
|
|
26
|
+
/**
|
|
27
|
+
* The child content displayed in the body.
|
|
28
|
+
*/
|
|
29
|
+
set childContent(value: DocumentFragment);
|
|
26
30
|
/**
|
|
27
31
|
* A contextual modifier.
|
|
28
32
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/Toast.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,EAAiB,MAAM,
|
|
1
|
+
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/Toast.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,EAAiB,MAAM,eAAe,CAAC;AAEtD;;GAEG;AACH,qBAAa,KAAM,SAAQ,WAAW;;IAErC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAA6C;IAkC/E;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,EAG3B;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAG1B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,EAExB;IAED;;OAEG;IACH,IAAI,YAAY,CAAC,KAAK,EAAE,gBAAgB,EAEvC;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAGrB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,CAGzB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAE7B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAkB/F;;OAEG;IACH,iBAAiB,IAAI,IAAI;IASzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,IAAI,IAAI,IAAI;CA+DZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,cAAc,EAAE,KAAK,CAAC;KACtB;CACD"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Duration } from "@cedx/base/Duration.js";
|
|
2
|
-
import { Context, getIcon, toCss } from "@cedx/base/UI/Context.js";
|
|
3
1
|
import { Toast as BootstrapToast } from "bootstrap";
|
|
2
|
+
import { Context, getIcon, toCss } from "../Context.js";
|
|
4
3
|
/**
|
|
5
4
|
* Represents a notification.
|
|
6
5
|
*/
|
|
@@ -17,10 +16,6 @@ export class Toast extends HTMLElement {
|
|
|
17
16
|
* The formatter used to format the relative time.
|
|
18
17
|
*/
|
|
19
18
|
#formatter;
|
|
20
|
-
/**
|
|
21
|
-
* The toast header.
|
|
22
|
-
*/
|
|
23
|
-
#header = this.querySelector(".toast-header");
|
|
24
19
|
/**
|
|
25
20
|
* The time at which this component was initially shown.
|
|
26
21
|
*/
|
|
@@ -72,6 +67,12 @@ export class Toast extends HTMLElement {
|
|
|
72
67
|
set caption(value) {
|
|
73
68
|
this.setAttribute("caption", value);
|
|
74
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* The child content displayed in the body.
|
|
72
|
+
*/
|
|
73
|
+
set childContent(value) {
|
|
74
|
+
this.querySelector(".toast-body").replaceChildren(...value.childNodes);
|
|
75
|
+
}
|
|
75
76
|
/**
|
|
76
77
|
* A contextual modifier.
|
|
77
78
|
*/
|
|
@@ -97,7 +98,7 @@ export class Toast extends HTMLElement {
|
|
|
97
98
|
*/
|
|
98
99
|
get delay() {
|
|
99
100
|
const value = Number(this.getAttribute("delay"));
|
|
100
|
-
return Math.max(
|
|
101
|
+
return Math.max(0, Number.isNaN(value) ? 5_000 : value);
|
|
101
102
|
}
|
|
102
103
|
set delay(value) {
|
|
103
104
|
this.setAttribute("delay", value.toString());
|
|
@@ -113,7 +114,7 @@ export class Toast extends HTMLElement {
|
|
|
113
114
|
*/
|
|
114
115
|
get icon() {
|
|
115
116
|
const value = this.getAttribute("icon") ?? "";
|
|
116
|
-
return value.trim() || getIcon(
|
|
117
|
+
return value.trim() || getIcon(this.context);
|
|
117
118
|
}
|
|
118
119
|
set icon(value) {
|
|
119
120
|
this.setAttribute("icon", value);
|
|
@@ -148,7 +149,7 @@ export class Toast extends HTMLElement {
|
|
|
148
149
|
connectedCallback() {
|
|
149
150
|
const toast = this.querySelector(".toast");
|
|
150
151
|
toast.addEventListener("hidden.bs.toast", () => clearInterval(this.#timer));
|
|
151
|
-
toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(this.#updateElapsedTime,
|
|
152
|
+
toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(this.#updateElapsedTime, 1_000));
|
|
152
153
|
const { animation, autoHide: autohide, delay } = this;
|
|
153
154
|
this.#toast = new BootstrapToast(toast, { animation, autohide, delay });
|
|
154
155
|
}
|
|
@@ -193,7 +194,7 @@ export class Toast extends HTMLElement {
|
|
|
193
194
|
* @param value The new value.
|
|
194
195
|
*/
|
|
195
196
|
#updateCaption(value) {
|
|
196
|
-
this
|
|
197
|
+
this.querySelector(".toast-header b").textContent = value.trim();
|
|
197
198
|
}
|
|
198
199
|
/**
|
|
199
200
|
* Updates the title displayed in the header.
|
|
@@ -201,25 +202,25 @@ export class Toast extends HTMLElement {
|
|
|
201
202
|
*/
|
|
202
203
|
#updateContext(value) {
|
|
203
204
|
const contexts = Object.values(Context);
|
|
204
|
-
let { classList } = this
|
|
205
|
+
let { classList } = this.querySelector(".toast-header");
|
|
205
206
|
classList.remove(...contexts.map(context => `toast-header-${toCss(context)}`));
|
|
206
|
-
classList.add(`toast-header-${value}`);
|
|
207
|
-
({ classList } = this
|
|
207
|
+
classList.add(`toast-header-${toCss(value)}`);
|
|
208
|
+
({ classList } = this.querySelector(".toast-header .icon"));
|
|
208
209
|
classList.remove(...contexts.map(context => `text-${toCss(context)}`));
|
|
209
|
-
classList.add(`text-${value}`);
|
|
210
|
+
classList.add(`text-${toCss(value)}`);
|
|
210
211
|
}
|
|
211
212
|
/**
|
|
212
213
|
* Updates the label corresponding to the elapsed time.
|
|
213
214
|
*/
|
|
214
215
|
#updateElapsedTime = () => {
|
|
215
216
|
const { elapsedTime } = this;
|
|
216
|
-
this
|
|
217
|
+
this.querySelector(".toast-header small").textContent = elapsedTime > 0 ? this.#formatTime(elapsedTime / 1_000) : "";
|
|
217
218
|
};
|
|
218
219
|
/**
|
|
219
220
|
* Updates the icon displayed next to the caption.
|
|
220
221
|
* @param value The new value.
|
|
221
222
|
*/
|
|
222
223
|
#updateIcon(value) {
|
|
223
|
-
this
|
|
224
|
+
this.querySelector(".toast-header .icon").textContent = value.trim() || getIcon(this.context);
|
|
224
225
|
}
|
|
225
226
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Context } from "../Context.js";
|
|
2
|
+
import { Position } from "../Position.js";
|
|
3
|
+
/**
|
|
4
|
+
* Represents a notification.
|
|
5
|
+
*/
|
|
6
|
+
export interface IToast {
|
|
7
|
+
/**
|
|
8
|
+
* Value indicating whether to apply a fade transition.
|
|
9
|
+
*/
|
|
10
|
+
animation?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Value indicating whether to automatically hide the toast.
|
|
13
|
+
*/
|
|
14
|
+
autoHide?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The title displayed in the header.
|
|
17
|
+
*/
|
|
18
|
+
caption: string;
|
|
19
|
+
/**
|
|
20
|
+
* The child content displayed in the body.
|
|
21
|
+
*/
|
|
22
|
+
childContent: DocumentFragment | string;
|
|
23
|
+
/**
|
|
24
|
+
* The default contextual modifier.
|
|
25
|
+
*/
|
|
26
|
+
context?: Context;
|
|
27
|
+
/**
|
|
28
|
+
* The culture used to format the relative time.
|
|
29
|
+
*/
|
|
30
|
+
culture?: Intl.Locale;
|
|
31
|
+
/**
|
|
32
|
+
* The delay, in milliseconds, to hide the toast.
|
|
33
|
+
*/
|
|
34
|
+
delay?: number;
|
|
35
|
+
/**
|
|
36
|
+
* The icon displayed next to the caption.
|
|
37
|
+
*/
|
|
38
|
+
icon?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Manages the notification messages.
|
|
42
|
+
*/
|
|
43
|
+
export declare class Toaster extends HTMLElement {
|
|
44
|
+
#private;
|
|
45
|
+
/**
|
|
46
|
+
* The list of observed attributes.
|
|
47
|
+
*/
|
|
48
|
+
static readonly observedAttributes: string[];
|
|
49
|
+
/**
|
|
50
|
+
* Value indicating whether to apply a fade transition.
|
|
51
|
+
*/
|
|
52
|
+
get animation(): boolean;
|
|
53
|
+
set animation(value: boolean);
|
|
54
|
+
/**
|
|
55
|
+
* Value indicating whether to automatically hide the toasts.
|
|
56
|
+
*/
|
|
57
|
+
get autoHide(): boolean;
|
|
58
|
+
set autoHide(value: boolean);
|
|
59
|
+
/**
|
|
60
|
+
* The default contextual modifier.
|
|
61
|
+
*/
|
|
62
|
+
get context(): Context;
|
|
63
|
+
set context(value: Context);
|
|
64
|
+
/**
|
|
65
|
+
* The default culture used to format the relative times.
|
|
66
|
+
*/
|
|
67
|
+
get culture(): Intl.Locale;
|
|
68
|
+
set culture(value: Intl.Locale);
|
|
69
|
+
/**
|
|
70
|
+
* The default delay, in milliseconds, to hide the toasts.
|
|
71
|
+
*/
|
|
72
|
+
get delay(): number;
|
|
73
|
+
set delay(value: number);
|
|
74
|
+
/**
|
|
75
|
+
* The default icon displayed next to the captions.
|
|
76
|
+
*/
|
|
77
|
+
get icon(): string;
|
|
78
|
+
set icon(value: string);
|
|
79
|
+
/**
|
|
80
|
+
* The toaster placement.
|
|
81
|
+
*/
|
|
82
|
+
get position(): Position;
|
|
83
|
+
set position(value: Position);
|
|
84
|
+
/**
|
|
85
|
+
* Method invoked when an attribute has been changed.
|
|
86
|
+
* @param attribute The attribute name.
|
|
87
|
+
* @param oldValue The previous attribute value.
|
|
88
|
+
* @param newValue The new attribute value.
|
|
89
|
+
*/
|
|
90
|
+
attributeChangedCallback(attribute: string, oldValue: string | null, newValue: string | null): void;
|
|
91
|
+
/**
|
|
92
|
+
* Shows a toast.
|
|
93
|
+
* @param context The contextual modifier.
|
|
94
|
+
* @param caption The title displayed in the toast header.
|
|
95
|
+
* @param childContent The child content displayed in the toast body.
|
|
96
|
+
*/
|
|
97
|
+
notify(context: Context, caption: string, childContent: DocumentFragment | string): void;
|
|
98
|
+
/**
|
|
99
|
+
* Shows the specified toast.
|
|
100
|
+
* @param toast The toast to show.
|
|
101
|
+
*/
|
|
102
|
+
show(toast: IToast): void;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Declaration merging.
|
|
106
|
+
*/
|
|
107
|
+
declare global {
|
|
108
|
+
/**
|
|
109
|
+
* The map of HTML tag names.
|
|
110
|
+
*/
|
|
111
|
+
interface HTMLElementTagNameMap {
|
|
112
|
+
"toaster-container": Toaster;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=Toaster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/Toaster.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAC,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,MAAM;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,YAAY,EAAE,gBAAgB,GAAC,MAAM,CAAC;IAEtC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;IAEtB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,OAAQ,SAAQ,WAAW;;IAEvC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAgB;IAclD;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,EAG3B;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAG1B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAGrB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,CAGzB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAE7B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,QAAQ,CAGvB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAE3B;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAS/F;;;;;OAKG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,gBAAgB,GAAC,MAAM,GAAG,IAAI;IAItF;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CA2BzB;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,OAAO,CAAC;KAC7B;CACD"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Context } from "../Context.js";
|
|
2
|
+
import { createDocumentFragment } from "../ElementExtensions.js";
|
|
3
|
+
import { Position, toCss } from "../Position.js";
|
|
4
|
+
/**
|
|
5
|
+
* Manages the notification messages.
|
|
6
|
+
*/
|
|
7
|
+
export class Toaster extends HTMLElement {
|
|
8
|
+
/**
|
|
9
|
+
* The list of observed attributes.
|
|
10
|
+
*/
|
|
11
|
+
static observedAttributes = ["position"];
|
|
12
|
+
/**
|
|
13
|
+
* The template for a toast.
|
|
14
|
+
*/
|
|
15
|
+
#toastTemplate = this.querySelector("template").content;
|
|
16
|
+
/**
|
|
17
|
+
* Registers the component.
|
|
18
|
+
*/
|
|
19
|
+
static {
|
|
20
|
+
customElements.define("toaster-container", this);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Value indicating whether to apply a fade transition.
|
|
24
|
+
*/
|
|
25
|
+
get animation() {
|
|
26
|
+
return this.hasAttribute("animation");
|
|
27
|
+
}
|
|
28
|
+
set animation(value) {
|
|
29
|
+
if (value)
|
|
30
|
+
this.setAttribute("animation", "");
|
|
31
|
+
else
|
|
32
|
+
this.removeAttribute("animation");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Value indicating whether to automatically hide the toasts.
|
|
36
|
+
*/
|
|
37
|
+
get autoHide() {
|
|
38
|
+
return this.hasAttribute("autohide");
|
|
39
|
+
}
|
|
40
|
+
set autoHide(value) {
|
|
41
|
+
if (value)
|
|
42
|
+
this.setAttribute("autohide", "");
|
|
43
|
+
else
|
|
44
|
+
this.removeAttribute("autohide");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The default contextual modifier.
|
|
48
|
+
*/
|
|
49
|
+
get context() {
|
|
50
|
+
const value = this.getAttribute("context");
|
|
51
|
+
return Object.values(Context).includes(value) ? value : Context.Info;
|
|
52
|
+
}
|
|
53
|
+
set context(value) {
|
|
54
|
+
this.setAttribute("context", value);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The default culture used to format the relative times.
|
|
58
|
+
*/
|
|
59
|
+
get culture() {
|
|
60
|
+
const value = this.getAttribute("culture") ?? "";
|
|
61
|
+
return new Intl.Locale(value.trim() || navigator.language);
|
|
62
|
+
}
|
|
63
|
+
set culture(value) {
|
|
64
|
+
this.setAttribute("culture", value.toString());
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The default delay, in milliseconds, to hide the toasts.
|
|
68
|
+
*/
|
|
69
|
+
get delay() {
|
|
70
|
+
const value = Number(this.getAttribute("delay"));
|
|
71
|
+
return Math.max(1, Number.isNaN(value) ? 5_000 : value);
|
|
72
|
+
}
|
|
73
|
+
set delay(value) {
|
|
74
|
+
this.setAttribute("delay", value.toString());
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The default icon displayed next to the captions.
|
|
78
|
+
*/
|
|
79
|
+
get icon() {
|
|
80
|
+
return (this.getAttribute("icon") ?? "").trim();
|
|
81
|
+
}
|
|
82
|
+
set icon(value) {
|
|
83
|
+
this.setAttribute("icon", value);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The toaster placement.
|
|
87
|
+
*/
|
|
88
|
+
get position() {
|
|
89
|
+
const value = this.getAttribute("position");
|
|
90
|
+
return Object.values(Position).includes(value) ? value : Position.BottomEnd;
|
|
91
|
+
}
|
|
92
|
+
set position(value) {
|
|
93
|
+
this.setAttribute("position", value);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Method invoked when an attribute has been changed.
|
|
97
|
+
* @param attribute The attribute name.
|
|
98
|
+
* @param oldValue The previous attribute value.
|
|
99
|
+
* @param newValue The new attribute value.
|
|
100
|
+
*/
|
|
101
|
+
attributeChangedCallback(attribute, oldValue, newValue) {
|
|
102
|
+
if (newValue != oldValue)
|
|
103
|
+
switch (attribute) {
|
|
104
|
+
case "position":
|
|
105
|
+
this.#updatePosition(Object.values(Position).includes(newValue) ? newValue : Position.BottomEnd);
|
|
106
|
+
break;
|
|
107
|
+
// No default
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Shows a toast.
|
|
112
|
+
* @param context The contextual modifier.
|
|
113
|
+
* @param caption The title displayed in the toast header.
|
|
114
|
+
* @param childContent The child content displayed in the toast body.
|
|
115
|
+
*/
|
|
116
|
+
notify(context, caption, childContent) {
|
|
117
|
+
this.show({ context, caption, childContent });
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Shows the specified toast.
|
|
121
|
+
* @param toast The toast to show.
|
|
122
|
+
*/
|
|
123
|
+
show(toast) {
|
|
124
|
+
const item = document.createElement("toaster-item");
|
|
125
|
+
item.addEventListener("hidden.bs.toast", () => item.remove());
|
|
126
|
+
item.appendChild(this.#toastTemplate.cloneNode(true).querySelector(".toast"));
|
|
127
|
+
item.animation = toast.animation ?? this.animation;
|
|
128
|
+
item.autoHide = toast.autoHide ?? this.autoHide;
|
|
129
|
+
item.caption = toast.caption;
|
|
130
|
+
item.childContent = typeof toast.childContent == "string" ? createDocumentFragment(toast.childContent) : toast.childContent;
|
|
131
|
+
item.context = toast.context ?? this.context;
|
|
132
|
+
item.culture = toast.culture ?? this.culture;
|
|
133
|
+
item.delay = toast.delay ?? this.delay;
|
|
134
|
+
item.icon = toast.icon ?? this.icon;
|
|
135
|
+
this.firstElementChild.appendChild(item);
|
|
136
|
+
item.show();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Updates the toaster placement.
|
|
140
|
+
* @param value The new value.
|
|
141
|
+
*/
|
|
142
|
+
#updatePosition(value) {
|
|
143
|
+
const { classList } = this.firstElementChild;
|
|
144
|
+
classList.remove(...Object.values(Position).flatMap(position => toCss(position).split(" ")));
|
|
145
|
+
classList.add(...toCss(value).split(" "));
|
|
146
|
+
}
|
|
147
|
+
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import {Duration} from "./Duration.js";
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Downloads the specified file.
|
|
5
3
|
* @param file The file to be downloaded.
|
|
@@ -38,7 +36,7 @@ export function open(file: File, options: {newTab?: boolean} = {}): void {
|
|
|
38
36
|
if (!handle.closed) return;
|
|
39
37
|
clearInterval(timer);
|
|
40
38
|
URL.revokeObjectURL(url);
|
|
41
|
-
},
|
|
39
|
+
}, 5_000);
|
|
42
40
|
}
|
|
43
41
|
|
|
44
42
|
/**
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component that moves back one page in the session history when clicked.
|
|
3
|
+
*/
|
|
4
|
+
export class BackButton extends HTMLElement {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new back button.
|
|
8
|
+
*/
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.addEventListener("click", () => history.go(-this.steps));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Registers the component.
|
|
16
|
+
*/
|
|
17
|
+
static {
|
|
18
|
+
customElements.define("back-button", this);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The number of pages to go back.
|
|
23
|
+
*/
|
|
24
|
+
get steps(): number {
|
|
25
|
+
const value = Number(this.getAttribute("steps"));
|
|
26
|
+
return Math.max(0, Number.isNaN(value) ? 1 : value);
|
|
27
|
+
}
|
|
28
|
+
set steps(value: number) {
|
|
29
|
+
this.setAttribute("steps", value.toString());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Declaration merging.
|
|
35
|
+
*/
|
|
36
|
+
declare global {
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The map of HTML tag names.
|
|
40
|
+
*/
|
|
41
|
+
interface HTMLElementTagNameMap {
|
|
42
|
+
"back-button": BackButton;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -29,7 +29,7 @@ export class LoadingIndicator extends HTMLElement {
|
|
|
29
29
|
*/
|
|
30
30
|
stop(options: {force?: boolean} = {}): void {
|
|
31
31
|
this.#requestCount--;
|
|
32
|
-
if (
|
|
32
|
+
if (this.#requestCount <= 0 || options.force) {
|
|
33
33
|
this.#requestCount = 0;
|
|
34
34
|
this.hidden = true;
|
|
35
35
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {Duration} from "@cedx/base/Duration.js";
|
|
2
|
-
import {Context, getIcon, toCss} from "@cedx/base/UI/Context.js";
|
|
3
1
|
import {Toast as BootstrapToast} from "bootstrap";
|
|
2
|
+
import {Context, getIcon, toCss} from "../Context.js";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Represents a notification.
|
|
@@ -22,11 +21,6 @@ export class Toast extends HTMLElement {
|
|
|
22
21
|
*/
|
|
23
22
|
#formatter!: Intl.RelativeTimeFormat;
|
|
24
23
|
|
|
25
|
-
/**
|
|
26
|
-
* The toast header.
|
|
27
|
-
*/
|
|
28
|
-
readonly #header = this.querySelector(".toast-header")!;
|
|
29
|
-
|
|
30
24
|
/**
|
|
31
25
|
* The time at which this component was initially shown.
|
|
32
26
|
*/
|
|
@@ -81,6 +75,13 @@ export class Toast extends HTMLElement {
|
|
|
81
75
|
this.setAttribute("caption", value);
|
|
82
76
|
}
|
|
83
77
|
|
|
78
|
+
/**
|
|
79
|
+
* The child content displayed in the body.
|
|
80
|
+
*/
|
|
81
|
+
set childContent(value: DocumentFragment) { // eslint-disable-line accessor-pairs
|
|
82
|
+
this.querySelector(".toast-body")!.replaceChildren(...value.childNodes);
|
|
83
|
+
}
|
|
84
|
+
|
|
84
85
|
/**
|
|
85
86
|
* A contextual modifier.
|
|
86
87
|
*/
|
|
@@ -108,7 +109,7 @@ export class Toast extends HTMLElement {
|
|
|
108
109
|
*/
|
|
109
110
|
get delay(): number {
|
|
110
111
|
const value = Number(this.getAttribute("delay"));
|
|
111
|
-
return Math.max(
|
|
112
|
+
return Math.max(0, Number.isNaN(value) ? 5_000 : value);
|
|
112
113
|
}
|
|
113
114
|
set delay(value: number) {
|
|
114
115
|
this.setAttribute("delay", value.toString());
|
|
@@ -126,7 +127,7 @@ export class Toast extends HTMLElement {
|
|
|
126
127
|
*/
|
|
127
128
|
get icon(): string {
|
|
128
129
|
const value = this.getAttribute("icon") ?? "";
|
|
129
|
-
return value.trim() || getIcon(
|
|
130
|
+
return value.trim() || getIcon(this.context);
|
|
130
131
|
}
|
|
131
132
|
set icon(value: string) {
|
|
132
133
|
this.setAttribute("icon", value);
|
|
@@ -140,10 +141,18 @@ export class Toast extends HTMLElement {
|
|
|
140
141
|
*/
|
|
141
142
|
attributeChangedCallback(attribute: string, oldValue: string|null, newValue: string|null): void {
|
|
142
143
|
if (newValue != oldValue) switch (attribute) {
|
|
143
|
-
case "caption":
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
case "
|
|
144
|
+
case "caption":
|
|
145
|
+
this.#updateCaption(newValue ?? "");
|
|
146
|
+
break;
|
|
147
|
+
case "context":
|
|
148
|
+
this.#updateContext(Object.values(Context).includes(newValue as Context) ? newValue as Context : Context.Info);
|
|
149
|
+
break;
|
|
150
|
+
case "culture":
|
|
151
|
+
this.#formatter = new Intl.RelativeTimeFormat((newValue ?? "").trim() || navigator.language, {style: "long"});
|
|
152
|
+
break;
|
|
153
|
+
case "icon":
|
|
154
|
+
this.#updateIcon(newValue ?? "");
|
|
155
|
+
break;
|
|
147
156
|
// No default
|
|
148
157
|
}
|
|
149
158
|
}
|
|
@@ -154,7 +163,7 @@ export class Toast extends HTMLElement {
|
|
|
154
163
|
connectedCallback(): void {
|
|
155
164
|
const toast = this.querySelector(".toast")!;
|
|
156
165
|
toast.addEventListener("hidden.bs.toast", () => clearInterval(this.#timer));
|
|
157
|
-
toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(this.#updateElapsedTime,
|
|
166
|
+
toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(this.#updateElapsedTime, 1_000));
|
|
158
167
|
|
|
159
168
|
const {animation, autoHide: autohide, delay} = this;
|
|
160
169
|
this.#toast = new BootstrapToast(toast, {animation, autohide, delay});
|
|
@@ -207,7 +216,7 @@ export class Toast extends HTMLElement {
|
|
|
207
216
|
* @param value The new value.
|
|
208
217
|
*/
|
|
209
218
|
#updateCaption(value: string): void {
|
|
210
|
-
this
|
|
219
|
+
this.querySelector(".toast-header b")!.textContent = value.trim();
|
|
211
220
|
}
|
|
212
221
|
|
|
213
222
|
/**
|
|
@@ -217,13 +226,13 @@ export class Toast extends HTMLElement {
|
|
|
217
226
|
#updateContext(value: Context): void {
|
|
218
227
|
const contexts = Object.values(Context);
|
|
219
228
|
|
|
220
|
-
let {classList} = this
|
|
229
|
+
let {classList} = this.querySelector(".toast-header")!;
|
|
221
230
|
classList.remove(...contexts.map(context => `toast-header-${toCss(context)}`));
|
|
222
|
-
classList.add(`toast-header-${value}`);
|
|
231
|
+
classList.add(`toast-header-${toCss(value)}`);
|
|
223
232
|
|
|
224
|
-
({classList} = this
|
|
233
|
+
({classList} = this.querySelector(".toast-header .icon")!);
|
|
225
234
|
classList.remove(...contexts.map(context => `text-${toCss(context)}`));
|
|
226
|
-
classList.add(`text-${value}`);
|
|
235
|
+
classList.add(`text-${toCss(value)}`);
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
/**
|
|
@@ -231,7 +240,7 @@ export class Toast extends HTMLElement {
|
|
|
231
240
|
*/
|
|
232
241
|
readonly #updateElapsedTime: () => void = () => {
|
|
233
242
|
const {elapsedTime} = this;
|
|
234
|
-
this
|
|
243
|
+
this.querySelector(".toast-header small")!.textContent = elapsedTime > 0 ? this.#formatTime(elapsedTime / 1_000) : "";
|
|
235
244
|
};
|
|
236
245
|
|
|
237
246
|
/**
|
|
@@ -239,7 +248,7 @@ export class Toast extends HTMLElement {
|
|
|
239
248
|
* @param value The new value.
|
|
240
249
|
*/
|
|
241
250
|
#updateIcon(value: string): void {
|
|
242
|
-
this
|
|
251
|
+
this.querySelector(".toast-header .icon")!.textContent = value.trim() || getIcon(this.context);
|
|
243
252
|
}
|
|
244
253
|
}
|
|
245
254
|
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import {Context} from "../Context.js";
|
|
2
|
+
import {createDocumentFragment} from "../ElementExtensions.js";
|
|
3
|
+
import {Position, toCss} from "../Position.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents a notification.
|
|
7
|
+
*/
|
|
8
|
+
export interface IToast {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Value indicating whether to apply a fade transition.
|
|
12
|
+
*/
|
|
13
|
+
animation?: boolean;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Value indicating whether to automatically hide the toast.
|
|
17
|
+
*/
|
|
18
|
+
autoHide?: boolean;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The title displayed in the header.
|
|
22
|
+
*/
|
|
23
|
+
caption: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The child content displayed in the body.
|
|
27
|
+
*/
|
|
28
|
+
childContent: DocumentFragment|string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The default contextual modifier.
|
|
32
|
+
*/
|
|
33
|
+
context?: Context;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The culture used to format the relative time.
|
|
37
|
+
*/
|
|
38
|
+
culture?: Intl.Locale;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The delay, in milliseconds, to hide the toast.
|
|
42
|
+
*/
|
|
43
|
+
delay?: number;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The icon displayed next to the caption.
|
|
47
|
+
*/
|
|
48
|
+
icon?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Manages the notification messages.
|
|
53
|
+
*/
|
|
54
|
+
export class Toaster extends HTMLElement {
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The list of observed attributes.
|
|
58
|
+
*/
|
|
59
|
+
static readonly observedAttributes = ["position"];
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The template for a toast.
|
|
63
|
+
*/
|
|
64
|
+
readonly #toastTemplate: DocumentFragment = this.querySelector("template")!.content;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Registers the component.
|
|
68
|
+
*/
|
|
69
|
+
static {
|
|
70
|
+
customElements.define("toaster-container", this);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Value indicating whether to apply a fade transition.
|
|
75
|
+
*/
|
|
76
|
+
get animation(): boolean {
|
|
77
|
+
return this.hasAttribute("animation");
|
|
78
|
+
}
|
|
79
|
+
set animation(value: boolean) {
|
|
80
|
+
if (value) this.setAttribute("animation", "");
|
|
81
|
+
else this.removeAttribute("animation");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Value indicating whether to automatically hide the toasts.
|
|
86
|
+
*/
|
|
87
|
+
get autoHide(): boolean {
|
|
88
|
+
return this.hasAttribute("autohide");
|
|
89
|
+
}
|
|
90
|
+
set autoHide(value: boolean) {
|
|
91
|
+
if (value) this.setAttribute("autohide", "");
|
|
92
|
+
else this.removeAttribute("autohide");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The default contextual modifier.
|
|
97
|
+
*/
|
|
98
|
+
get context(): Context {
|
|
99
|
+
const value = this.getAttribute("context") as Context;
|
|
100
|
+
return Object.values(Context).includes(value) ? value : Context.Info;
|
|
101
|
+
}
|
|
102
|
+
set context(value: Context) {
|
|
103
|
+
this.setAttribute("context", value);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The default culture used to format the relative times.
|
|
108
|
+
*/
|
|
109
|
+
get culture(): Intl.Locale {
|
|
110
|
+
const value = this.getAttribute("culture") ?? "";
|
|
111
|
+
return new Intl.Locale(value.trim() || navigator.language);
|
|
112
|
+
}
|
|
113
|
+
set culture(value: Intl.Locale) {
|
|
114
|
+
this.setAttribute("culture", value.toString());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The default delay, in milliseconds, to hide the toasts.
|
|
119
|
+
*/
|
|
120
|
+
get delay(): number {
|
|
121
|
+
const value = Number(this.getAttribute("delay"));
|
|
122
|
+
return Math.max(1, Number.isNaN(value) ? 5_000 : value);
|
|
123
|
+
}
|
|
124
|
+
set delay(value: number) {
|
|
125
|
+
this.setAttribute("delay", value.toString());
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The default icon displayed next to the captions.
|
|
130
|
+
*/
|
|
131
|
+
get icon(): string {
|
|
132
|
+
return (this.getAttribute("icon") ?? "").trim();
|
|
133
|
+
}
|
|
134
|
+
set icon(value: string) {
|
|
135
|
+
this.setAttribute("icon", value);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The toaster placement.
|
|
140
|
+
*/
|
|
141
|
+
get position(): Position {
|
|
142
|
+
const value = this.getAttribute("position") as Position;
|
|
143
|
+
return Object.values(Position).includes(value) ? value : Position.BottomEnd;
|
|
144
|
+
}
|
|
145
|
+
set position(value: Position) {
|
|
146
|
+
this.setAttribute("position", value);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Method invoked when an attribute has been changed.
|
|
151
|
+
* @param attribute The attribute name.
|
|
152
|
+
* @param oldValue The previous attribute value.
|
|
153
|
+
* @param newValue The new attribute value.
|
|
154
|
+
*/
|
|
155
|
+
attributeChangedCallback(attribute: string, oldValue: string|null, newValue: string|null): void {
|
|
156
|
+
if (newValue != oldValue) switch (attribute) {
|
|
157
|
+
case "position":
|
|
158
|
+
this.#updatePosition(Object.values(Position).includes(newValue as Position) ? newValue as Position : Position.BottomEnd);
|
|
159
|
+
break;
|
|
160
|
+
// No default
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Shows a toast.
|
|
166
|
+
* @param context The contextual modifier.
|
|
167
|
+
* @param caption The title displayed in the toast header.
|
|
168
|
+
* @param childContent The child content displayed in the toast body.
|
|
169
|
+
*/
|
|
170
|
+
notify(context: Context, caption: string, childContent: DocumentFragment|string): void {
|
|
171
|
+
this.show({context, caption, childContent});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Shows the specified toast.
|
|
176
|
+
* @param toast The toast to show.
|
|
177
|
+
*/
|
|
178
|
+
show(toast: IToast): void {
|
|
179
|
+
const item = document.createElement("toaster-item");
|
|
180
|
+
item.addEventListener("hidden.bs.toast", () => item.remove());
|
|
181
|
+
item.appendChild((this.#toastTemplate.cloneNode(true) as DocumentFragment).querySelector(".toast")!);
|
|
182
|
+
|
|
183
|
+
item.animation = toast.animation ?? this.animation;
|
|
184
|
+
item.autoHide = toast.autoHide ?? this.autoHide;
|
|
185
|
+
item.caption = toast.caption;
|
|
186
|
+
item.childContent = typeof toast.childContent == "string" ? createDocumentFragment(toast.childContent) : toast.childContent;
|
|
187
|
+
item.context = toast.context ?? this.context;
|
|
188
|
+
item.culture = toast.culture ?? this.culture;
|
|
189
|
+
item.delay = toast.delay ?? this.delay;
|
|
190
|
+
item.icon = toast.icon ?? this.icon;
|
|
191
|
+
|
|
192
|
+
this.firstElementChild!.appendChild(item);
|
|
193
|
+
item.show();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Updates the toaster placement.
|
|
198
|
+
* @param value The new value.
|
|
199
|
+
*/
|
|
200
|
+
#updatePosition(value: Position): void {
|
|
201
|
+
const {classList} = this.firstElementChild!;
|
|
202
|
+
classList.remove(...Object.values(Position).flatMap(position => toCss(position).split(" ")));
|
|
203
|
+
classList.add(...toCss(value).split(" "));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Declaration merging.
|
|
209
|
+
*/
|
|
210
|
+
declare global {
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The map of HTML tag names.
|
|
214
|
+
*/
|
|
215
|
+
interface HTMLElementTagNameMap {
|
|
216
|
+
"toaster-container": Toaster;
|
|
217
|
+
}
|
|
218
|
+
}
|