@cedx/ui 0.1.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/License.md +20 -0
- package/ReadMe.md +17 -0
- package/lib/Alignment.d.ts +22 -0
- package/lib/Alignment.d.ts.map +1 -0
- package/lib/Alignment.js +17 -0
- package/lib/AppTheme.d.ts +34 -0
- package/lib/AppTheme.d.ts.map +1 -0
- package/lib/AppTheme.js +41 -0
- package/lib/Components/BackButton.d.ts +27 -0
- package/lib/Components/BackButton.d.ts.map +1 -0
- package/lib/Components/BackButton.js +29 -0
- package/lib/Components/DialogBox.d.ts +151 -0
- package/lib/Components/DialogBox.d.ts.map +1 -0
- package/lib/Components/DialogBox.js +268 -0
- package/lib/Components/FullScreenToggler.d.ts +42 -0
- package/lib/Components/FullScreenToggler.d.ts.map +1 -0
- package/lib/Components/FullScreenToggler.js +103 -0
- package/lib/Components/KeyboardAccelerator.d.ts +36 -0
- package/lib/Components/KeyboardAccelerator.d.ts.map +1 -0
- package/lib/Components/KeyboardAccelerator.js +78 -0
- package/lib/Components/LoadingIndicator.d.ts +58 -0
- package/lib/Components/LoadingIndicator.d.ts.map +1 -0
- package/lib/Components/LoadingIndicator.js +93 -0
- package/lib/Components/MenuActivator.d.ts +26 -0
- package/lib/Components/MenuActivator.d.ts.map +1 -0
- package/lib/Components/MenuActivator.js +42 -0
- package/lib/Components/OfflineIndicator.d.ts +59 -0
- package/lib/Components/OfflineIndicator.d.ts.map +1 -0
- package/lib/Components/OfflineIndicator.js +106 -0
- package/lib/Components/TabActivator.d.ts +49 -0
- package/lib/Components/TabActivator.d.ts.map +1 -0
- package/lib/Components/TabActivator.js +70 -0
- package/lib/Components/ThemeDropdown.d.ts +86 -0
- package/lib/Components/ThemeDropdown.d.ts.map +1 -0
- package/lib/Components/ThemeDropdown.js +207 -0
- package/lib/Components/Toast.d.ts +94 -0
- package/lib/Components/Toast.d.ts.map +1 -0
- package/lib/Components/Toast.js +284 -0
- package/lib/Components/Toaster.d.ts +119 -0
- package/lib/Components/Toaster.d.ts.map +1 -0
- package/lib/Components/Toaster.js +153 -0
- package/lib/Components/TypeAhead.d.ts +53 -0
- package/lib/Components/TypeAhead.d.ts.map +1 -0
- package/lib/Components/TypeAhead.js +138 -0
- package/lib/Context.d.ts +38 -0
- package/lib/Context.d.ts.map +1 -0
- package/lib/Context.js +42 -0
- package/lib/DialogResult.d.ts +30 -0
- package/lib/DialogResult.d.ts.map +1 -0
- package/lib/DialogResult.js +29 -0
- package/lib/File.d.ts +25 -0
- package/lib/File.d.ts.map +1 -0
- package/lib/File.js +66 -0
- package/lib/Form.d.ts +33 -0
- package/lib/Form.d.ts.map +1 -0
- package/lib/Form.js +50 -0
- package/lib/Htmx.d.ts +12 -0
- package/lib/Htmx.d.ts.map +1 -0
- package/lib/Htmx.js +2 -0
- package/lib/KeyboardModifiers.d.ts +26 -0
- package/lib/KeyboardModifiers.d.ts.map +1 -0
- package/lib/KeyboardModifiers.js +25 -0
- package/lib/Position.d.ts +52 -0
- package/lib/Position.d.ts.map +1 -0
- package/lib/Position.js +59 -0
- package/lib/Size.d.ts +40 -0
- package/lib/Size.d.ts.map +1 -0
- package/lib/Size.js +44 -0
- package/lib/StorageArea.d.ts +18 -0
- package/lib/StorageArea.d.ts.map +1 -0
- package/lib/StorageArea.js +13 -0
- package/lib/Tags.d.ts +15 -0
- package/lib/Tags.d.ts.map +1 -0
- package/lib/Tags.js +48 -0
- package/lib/Variant.d.ts +36 -0
- package/lib/Variant.d.ts.map +1 -0
- package/lib/Variant.js +31 -0
- package/lib/ViewportScroller.d.ts +49 -0
- package/lib/ViewportScroller.d.ts.map +1 -0
- package/lib/ViewportScroller.js +69 -0
- package/package.json +58 -0
- package/src/Client/Alignment.ts +25 -0
- package/src/Client/AppTheme.ts +51 -0
- package/src/Client/Components/BackButton.ts +45 -0
- package/src/Client/Components/DialogBox.ts +344 -0
- package/src/Client/Components/FullScreenToggler.ts +122 -0
- package/src/Client/Components/KeyboardAccelerator.ts +97 -0
- package/src/Client/Components/LoadingIndicator.ts +113 -0
- package/src/Client/Components/MenuActivator.ts +58 -0
- package/src/Client/Components/OfflineIndicator.ts +125 -0
- package/src/Client/Components/TabActivator.ts +93 -0
- package/src/Client/Components/ThemeDropdown.ts +235 -0
- package/src/Client/Components/Toast.ts +319 -0
- package/src/Client/Components/Toaster.ts +224 -0
- package/src/Client/Components/TypeAhead.ts +153 -0
- package/src/Client/Context.ts +53 -0
- package/src/Client/DialogResult.ts +35 -0
- package/src/Client/File.ts +73 -0
- package/src/Client/Form.ts +55 -0
- package/src/Client/Htmx.ts +13 -0
- package/src/Client/KeyboardModifiers.ts +30 -0
- package/src/Client/Position.ts +74 -0
- package/src/Client/Size.ts +56 -0
- package/src/Client/StorageArea.ts +20 -0
- package/src/Client/Tags.ts +58 -0
- package/src/Client/Variant.ts +42 -0
- package/src/Client/ViewportScroller.ts +89 -0
- package/src/Client/tsconfig.json +19 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component that activates the items of a menu, based on the current document URL.
|
|
3
|
+
*/
|
|
4
|
+
export class MenuActivator extends HTMLElement {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The abort controller used to remove the event listeners.
|
|
8
|
+
*/
|
|
9
|
+
#abortController: AbortController|null = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Registers the component.
|
|
13
|
+
*/
|
|
14
|
+
static {
|
|
15
|
+
customElements.define("menu-activator", this);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Method invoked when this component is connected.
|
|
20
|
+
*/
|
|
21
|
+
connectedCallback(): void {
|
|
22
|
+
this.#abortController = new AbortController;
|
|
23
|
+
this.#update();
|
|
24
|
+
addEventListener("popstate", () => this.#update(), {signal: this.#abortController.signal});
|
|
25
|
+
document.body.addEventListener("htmx:pushedIntoHistory", () => this.#update(), {signal: this.#abortController.signal});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Method invoked when this component is disconnected.
|
|
30
|
+
*/
|
|
31
|
+
disconnectedCallback(): void {
|
|
32
|
+
this.#abortController?.abort();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Updates this component.
|
|
37
|
+
*/
|
|
38
|
+
#update(): void {
|
|
39
|
+
for (const element of this.querySelectorAll(".active")) element.classList.remove("active");
|
|
40
|
+
for (const element of this.querySelectorAll("a")) if (element.href == location.href) {
|
|
41
|
+
element.classList.add("active");
|
|
42
|
+
element.closest(".dropdown")?.querySelector(".dropdown-toggle")?.classList.add("active");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Declaration merging.
|
|
49
|
+
*/
|
|
50
|
+
declare global {
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The map of HTML tag names.
|
|
54
|
+
*/
|
|
55
|
+
interface HTMLElementTagNameMap {
|
|
56
|
+
"menu-activator": MenuActivator;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component that shows up when the network is unavailable, and hides when connectivity is restored.
|
|
3
|
+
*/
|
|
4
|
+
export class OfflineIndicator extends HTMLElement {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The list of observed attributes.
|
|
8
|
+
*/
|
|
9
|
+
static readonly observedAttributes = ["fade"];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The abort controller used to remove the event listeners.
|
|
13
|
+
*/
|
|
14
|
+
#abortController: AbortController|null = null;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Registers the component.
|
|
18
|
+
*/
|
|
19
|
+
static {
|
|
20
|
+
customElements.define("offline-indicator", this);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Value indicating whether to apply a transition.
|
|
25
|
+
*/
|
|
26
|
+
get fade(): boolean {
|
|
27
|
+
return this.hasAttribute("fade");
|
|
28
|
+
}
|
|
29
|
+
set fade(value: boolean) {
|
|
30
|
+
this.toggleAttribute("fade", value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Value indicating whether this component is shown.
|
|
35
|
+
*/
|
|
36
|
+
get isShown(): boolean {
|
|
37
|
+
return this.classList.contains("show");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Value indicating whether to initially show this component.
|
|
42
|
+
*/
|
|
43
|
+
get open(): boolean {
|
|
44
|
+
return this.hasAttribute("open");
|
|
45
|
+
}
|
|
46
|
+
set open(value: boolean) {
|
|
47
|
+
this.toggleAttribute("open", value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Method invoked when an attribute has been changed.
|
|
52
|
+
* @param attribute The attribute name.
|
|
53
|
+
* @param oldValue The previous attribute value.
|
|
54
|
+
* @param newValue The new attribute value.
|
|
55
|
+
*/
|
|
56
|
+
attributeChangedCallback(attribute: string, oldValue: string|null, newValue: string|null): void {
|
|
57
|
+
if (newValue != oldValue) switch (attribute) {
|
|
58
|
+
case "fade": this.#updateFade(newValue != null); break;
|
|
59
|
+
// No default
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Method invoked when this component is connected.
|
|
65
|
+
*/
|
|
66
|
+
connectedCallback(): void {
|
|
67
|
+
this.#abortController = new AbortController;
|
|
68
|
+
for (const event of ["online", "offline"]) addEventListener(event, () => this.#updateVisibility(), {signal: this.#abortController.signal});
|
|
69
|
+
|
|
70
|
+
if (this.open) this.show();
|
|
71
|
+
else this.#updateVisibility();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Method invoked when this component is disconnected.
|
|
76
|
+
*/
|
|
77
|
+
disconnectedCallback(): void {
|
|
78
|
+
this.#abortController?.abort();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Hides this offline indicator.
|
|
83
|
+
*/
|
|
84
|
+
hide(): void {
|
|
85
|
+
this.classList.remove("show");
|
|
86
|
+
this.classList.add("hide");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Shows this offline indicator.
|
|
91
|
+
*/
|
|
92
|
+
show(): void {
|
|
93
|
+
this.classList.remove("hide");
|
|
94
|
+
this.classList.add("show");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Updates the value indicating whether to apply a transition.
|
|
99
|
+
* @param value The new value.
|
|
100
|
+
*/
|
|
101
|
+
#updateFade(value: boolean): void {
|
|
102
|
+
this.classList.toggle("fade", value);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Updates the visibility of this component.
|
|
107
|
+
*/
|
|
108
|
+
#updateVisibility(): void {
|
|
109
|
+
if (navigator.onLine) this.hide();
|
|
110
|
+
else this.show();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Declaration merging.
|
|
116
|
+
*/
|
|
117
|
+
declare global {
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The map of HTML tag names.
|
|
121
|
+
*/
|
|
122
|
+
interface HTMLElementTagNameMap {
|
|
123
|
+
"offline-indicator": OfflineIndicator;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {Tab} from "bootstrap";
|
|
2
|
+
import {StorageArea} from "../StorageArea.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A component that activates a tab, based on its index saved in the web storage.
|
|
6
|
+
*/
|
|
7
|
+
export class TabActivator extends HTMLElement {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new tab activator.
|
|
11
|
+
*/
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
|
|
15
|
+
const {tabs} = this;
|
|
16
|
+
for (let index = 0; index < tabs.length; index++)
|
|
17
|
+
tabs.item(index).addEventListener("show.bs.tab", () => this.activeTabIndex = index);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Registers the component.
|
|
22
|
+
*/
|
|
23
|
+
static {
|
|
24
|
+
customElements.define("tab-activator", this);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The index of the active tab.
|
|
29
|
+
*/
|
|
30
|
+
get activeTabIndex(): number {
|
|
31
|
+
const index = Number(this.storage.getItem(this.storageKey) ?? "0");
|
|
32
|
+
return Math.max(0, Math.min(this.tabs.length - 1, Number.isNaN(index) ? 0 : index));
|
|
33
|
+
}
|
|
34
|
+
set activeTabIndex(value: number) {
|
|
35
|
+
this.storage.setItem(this.storageKey, value.toString());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The storage object corresponding to the current {@link storageArea}.
|
|
40
|
+
*/
|
|
41
|
+
get storage(): globalThis.Storage {
|
|
42
|
+
return this.storageArea == StorageArea.Local ? localStorage : sessionStorage;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The storage area to use.
|
|
47
|
+
*/
|
|
48
|
+
get storageArea(): StorageArea {
|
|
49
|
+
const value = this.getAttribute("storagearea") as StorageArea;
|
|
50
|
+
return Object.values(StorageArea).includes(value) ? value : StorageArea.Session;
|
|
51
|
+
}
|
|
52
|
+
set storageArea(value: StorageArea) {
|
|
53
|
+
this.setAttribute("storagearea", value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The key of the storage entry providing the active tab index.
|
|
58
|
+
*/
|
|
59
|
+
get storageKey(): string {
|
|
60
|
+
const value = this.getAttribute("storagekey") ?? "";
|
|
61
|
+
return value.trim() || "ActiveTabIndex";
|
|
62
|
+
}
|
|
63
|
+
set storageKey(value: string) {
|
|
64
|
+
this.setAttribute("storagekey", value);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The tab list.
|
|
69
|
+
*/
|
|
70
|
+
get tabs(): NodeListOf<HTMLElement> {
|
|
71
|
+
return this.querySelectorAll('[data-bs-toggle="tab"]');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Method invoked when this component is connected.
|
|
76
|
+
*/
|
|
77
|
+
connectedCallback(): void {
|
|
78
|
+
Tab.getOrCreateInstance(this.tabs.item(this.activeTabIndex)).show();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Declaration merging.
|
|
84
|
+
*/
|
|
85
|
+
declare global {
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The map of HTML tag names.
|
|
89
|
+
*/
|
|
90
|
+
interface HTMLElementTagNameMap {
|
|
91
|
+
"tab-activator": TabActivator;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import {Dropdown} from "bootstrap";
|
|
2
|
+
import {Alignment} from "../Alignment.js";
|
|
3
|
+
import {AppTheme, icon} from "../AppTheme.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A dropdown menu for switching the application theme.
|
|
7
|
+
*/
|
|
8
|
+
export class ThemeDropdown extends HTMLElement {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The list of observed attributes.
|
|
12
|
+
*/
|
|
13
|
+
static readonly observedAttributes = ["alignment", "apptheme", "label"];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The abort controller used to remove the event listeners.
|
|
17
|
+
*/
|
|
18
|
+
#abortController: AbortController|null = null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The dropdown menu.
|
|
22
|
+
*/
|
|
23
|
+
#dropdown!: Dropdown;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The media query used to check the application theme.
|
|
27
|
+
*/
|
|
28
|
+
readonly #mediaQuery = matchMedia("(prefers-color-scheme: dark)");
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new theme dropdown.
|
|
32
|
+
*/
|
|
33
|
+
constructor() {
|
|
34
|
+
super();
|
|
35
|
+
for (const button of this.querySelectorAll(".dropdown-menu button")) button.addEventListener("click", this.#setAppTheme);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Registers the component.
|
|
40
|
+
*/
|
|
41
|
+
static {
|
|
42
|
+
customElements.define("theme-dropdown", this);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The alignment of the dropdown menu.
|
|
47
|
+
*/
|
|
48
|
+
get alignment(): Alignment {
|
|
49
|
+
const value = this.getAttribute("alignment") as Alignment;
|
|
50
|
+
return Object.values(Alignment).includes(value) ? value : Alignment.End;
|
|
51
|
+
}
|
|
52
|
+
set alignment(value: Alignment) {
|
|
53
|
+
this.setAttribute("alignment", value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The current application theme.
|
|
58
|
+
*/
|
|
59
|
+
get appTheme(): AppTheme {
|
|
60
|
+
const value = this.getAttribute("apptheme") as AppTheme;
|
|
61
|
+
return Object.values(AppTheme).includes(value) ? value : AppTheme.System;
|
|
62
|
+
}
|
|
63
|
+
set appTheme(value: AppTheme) {
|
|
64
|
+
this.setAttribute("apptheme", value);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Value indicating whether to store the application theme in a cookie.
|
|
69
|
+
*/
|
|
70
|
+
get cookie(): boolean {
|
|
71
|
+
return this.hasAttribute("cookie");
|
|
72
|
+
}
|
|
73
|
+
set cookie(value: boolean) {
|
|
74
|
+
this.toggleAttribute("cookie", value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The URI for which the associated cookie is valid.
|
|
79
|
+
*/
|
|
80
|
+
get cookieDomain(): string {
|
|
81
|
+
return (this.getAttribute("cookiedomain") ?? "").trim();
|
|
82
|
+
}
|
|
83
|
+
set cookieDomain(value: string) {
|
|
84
|
+
this.setAttribute("cookiedomain", value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The label of the dropdown menu.
|
|
89
|
+
*/
|
|
90
|
+
get label(): string {
|
|
91
|
+
const value = this.getAttribute("label") ?? "";
|
|
92
|
+
return value.trim() || "Thème";
|
|
93
|
+
}
|
|
94
|
+
set label(value: string) {
|
|
95
|
+
this.setAttribute("label", value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The key of the storage entry providing the saved application theme.
|
|
100
|
+
*/
|
|
101
|
+
get storageKey(): string {
|
|
102
|
+
const value = this.getAttribute("storagekey") ?? "";
|
|
103
|
+
return value.trim() || "AppTheme";
|
|
104
|
+
}
|
|
105
|
+
set storageKey(value: string) {
|
|
106
|
+
this.setAttribute("storagekey", value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Method invoked when an attribute has been changed.
|
|
111
|
+
* @param attribute The attribute name.
|
|
112
|
+
* @param oldValue The previous attribute value.
|
|
113
|
+
* @param newValue The new attribute value.
|
|
114
|
+
*/
|
|
115
|
+
attributeChangedCallback(attribute: string, oldValue: string|null, newValue: string|null): void {
|
|
116
|
+
if (newValue != oldValue) switch (attribute) {
|
|
117
|
+
case "alignment": this.#updateAlignment(Object.values(Alignment).includes(newValue as Alignment) ? newValue as Alignment : Alignment.End); break;
|
|
118
|
+
case "apptheme": this.#updateAppTheme(Object.values(AppTheme).includes(newValue as AppTheme) ? newValue as AppTheme : AppTheme.System); break;
|
|
119
|
+
case "label": this.#updateLabel(newValue ?? ""); break;
|
|
120
|
+
// No default
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Closes the dropdown menu.
|
|
126
|
+
*/
|
|
127
|
+
close(): void {
|
|
128
|
+
this.#dropdown.hide();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Method invoked when this component is connected.
|
|
133
|
+
* @returns Completes when this component has been connected.
|
|
134
|
+
*/
|
|
135
|
+
async connectedCallback(): Promise<void> {
|
|
136
|
+
this.#abortController = new AbortController;
|
|
137
|
+
this.#dropdown = new Dropdown(this.querySelector(".dropdown-toggle")!);
|
|
138
|
+
this.#mediaQuery.addEventListener("change", () => this.#applyToDocument(), {signal: this.#abortController.signal});
|
|
139
|
+
|
|
140
|
+
const cookie = this.cookie ? await cookieStore.get(this.storageKey) : null;
|
|
141
|
+
if (cookie) this.appTheme = cookie.value as AppTheme;
|
|
142
|
+
else {
|
|
143
|
+
const storage = localStorage.getItem(this.storageKey);
|
|
144
|
+
if (storage) this.appTheme = storage as AppTheme;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Method invoked when this component is disconnected.
|
|
150
|
+
*/
|
|
151
|
+
disconnectedCallback(): void {
|
|
152
|
+
this.#abortController?.abort();
|
|
153
|
+
this.#dropdown.dispose();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Opens the dropdown menu.
|
|
158
|
+
*/
|
|
159
|
+
open(): void {
|
|
160
|
+
this.#dropdown.show();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Saves the current application theme into the local storage.
|
|
165
|
+
*/
|
|
166
|
+
save(): void {
|
|
167
|
+
const {appTheme, cookieDomain} = this;
|
|
168
|
+
localStorage.setItem(this.storageKey, appTheme);
|
|
169
|
+
|
|
170
|
+
if (this.cookie) void cookieStore.set({
|
|
171
|
+
domain: cookieDomain ? cookieDomain : null,
|
|
172
|
+
expires: Date.now() + (365 * 24 * 60 * 60 * 1_000),
|
|
173
|
+
name: this.storageKey,
|
|
174
|
+
value: appTheme
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Applies the application theme to the document.
|
|
180
|
+
*/
|
|
181
|
+
#applyToDocument(): void {
|
|
182
|
+
const {appTheme} = this;
|
|
183
|
+
const bsTheme = appTheme == AppTheme.System ? (this.#mediaQuery.matches ? AppTheme.Dark : AppTheme.Light) : appTheme;
|
|
184
|
+
document.documentElement.dataset.bsTheme = bsTheme.toLowerCase();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Changes the current application theme.
|
|
189
|
+
* @param event The dispatched event.
|
|
190
|
+
*/
|
|
191
|
+
readonly #setAppTheme: (event: Event) => void = event => {
|
|
192
|
+
event.preventDefault();
|
|
193
|
+
this.appTheme = (event.currentTarget as HTMLButtonElement).value as AppTheme;
|
|
194
|
+
this.save();
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Updates the alignment of the dropdown menu.
|
|
199
|
+
* @param value The new value.
|
|
200
|
+
*/
|
|
201
|
+
#updateAlignment(value: Alignment): void {
|
|
202
|
+
this.querySelector(".dropdown-menu")!.classList.toggle("dropdown-menu-end", value == Alignment.End);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Updates the application theme.
|
|
207
|
+
* @param value The new value.
|
|
208
|
+
*/
|
|
209
|
+
#updateAppTheme(value: AppTheme): void {
|
|
210
|
+
this.querySelector(".dropdown-toggle > .icon")!.textContent = icon(value);
|
|
211
|
+
this.querySelector(`.dropdown-menu button[value="${value}"]`)!.appendChild(this.querySelector(".dropdown-item > .icon")!);
|
|
212
|
+
this.#applyToDocument();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Updates the label of the dropdown menu.
|
|
217
|
+
* @param value The new value.
|
|
218
|
+
*/
|
|
219
|
+
#updateLabel(value: string): void {
|
|
220
|
+
this.querySelector(".dropdown-toggle > span")!.textContent = value.trim() || "Thème";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Declaration merging.
|
|
226
|
+
*/
|
|
227
|
+
declare global {
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* The map of HTML tag names.
|
|
231
|
+
*/
|
|
232
|
+
interface HTMLElementTagNameMap {
|
|
233
|
+
"theme-dropdown": ThemeDropdown;
|
|
234
|
+
}
|
|
235
|
+
}
|