@cedx/base 0.10.0 → 0.11.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 (38) hide show
  1. package/ReadMe.md +1 -1
  2. package/lib/Data/Pagination.d.ts +3 -3
  3. package/lib/Data/Pagination.js +10 -10
  4. package/lib/UI/Components/KeyboardAccelerator.d.ts +11 -0
  5. package/lib/UI/Components/KeyboardAccelerator.d.ts.map +1 -1
  6. package/lib/UI/Components/KeyboardAccelerator.js +5 -5
  7. package/lib/UI/Components/MenuActivator.js +1 -1
  8. package/lib/UI/Components/OfflineIndicator.d.ts +0 -4
  9. package/lib/UI/Components/OfflineIndicator.d.ts.map +1 -1
  10. package/lib/UI/Components/OfflineIndicator.js +1 -7
  11. package/lib/UI/Components/TabActivator.d.ts +1 -1
  12. package/lib/UI/Components/TabActivator.js +7 -7
  13. package/lib/UI/Components/ThemeDropdown.d.ts +4 -0
  14. package/lib/UI/Components/ThemeDropdown.d.ts.map +1 -1
  15. package/lib/UI/Components/ThemeDropdown.js +9 -5
  16. package/lib/UI/ElementExtensions.d.ts +13 -0
  17. package/lib/UI/ElementExtensions.d.ts.map +1 -0
  18. package/lib/UI/ElementExtensions.js +18 -0
  19. package/lib/UI/Size.d.ts +34 -0
  20. package/lib/UI/Size.d.ts.map +1 -0
  21. package/lib/UI/Size.js +29 -0
  22. package/lib/UI/Variant.d.ts +26 -0
  23. package/lib/UI/Variant.d.ts.map +1 -0
  24. package/lib/UI/Variant.js +21 -0
  25. package/lib/UI/ViewportScroller.js +1 -1
  26. package/package.json +5 -5
  27. package/src/Client/Data/Pagination.ts +11 -11
  28. package/src/Client/UI/Components/KeyboardAccelerator.ts +18 -5
  29. package/src/Client/UI/Components/MenuActivator.ts +1 -1
  30. package/src/Client/UI/Components/MessageBox.old +242 -0
  31. package/src/Client/UI/Components/OfflineIndicator.ts +1 -8
  32. package/src/Client/UI/Components/TabActivator.ts +7 -7
  33. package/src/Client/UI/Components/ThemeDropdown.ts +9 -4
  34. package/src/Client/UI/Components/Toaster.old +0 -0
  35. package/src/Client/UI/ElementExtensions.ts +19 -0
  36. package/src/Client/UI/Size.ts +40 -0
  37. package/src/Client/UI/Variant.ts +30 -0
  38. package/src/Client/UI/ViewportScroller.ts +1 -1
package/ReadMe.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Belin.io Base
2
- ![.NET](https://badgen.net/badge/.net/%3E%3D9.0/green) ![Version](https://badgen.net/badge/project/v0.10.0/blue) ![Licence](https://badgen.net/badge/licence/MIT/blue)
2
+ ![.NET](https://badgen.net/badge/.net/%3E%3D9.0/green) ![Version](https://badgen.net/badge/project/v0.11.0/blue) ![Licence](https://badgen.net/badge/licence/MIT/blue)
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).
@@ -9,7 +9,7 @@ export declare class Pagination {
9
9
  */
10
10
  constructor(options?: PaginationOptions);
11
11
  /**
12
- * The one-based current page number.
12
+ * The current page index.
13
13
  */
14
14
  get currentPageIndex(): number;
15
15
  set currentPageIndex(value: number);
@@ -27,7 +27,7 @@ export declare class Pagination {
27
27
  get itemsPerPage(): number;
28
28
  set itemsPerPage(value: number);
29
29
  /**
30
- * The one-based last page number.
30
+ * The last page index.
31
31
  */
32
32
  get lastPageIndex(): number;
33
33
  /**
@@ -59,7 +59,7 @@ export declare class Pagination {
59
59
  */
60
60
  export type PaginationOptions = Partial<{
61
61
  /**
62
- * The one-based current page number.
62
+ * The current page index.
63
63
  */
64
64
  currentPageIndex: number;
65
65
  /**
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export class Pagination {
5
5
  /**
6
- * The one-based current page number.
6
+ * The current page index.
7
7
  */
8
8
  #currentPageIndex;
9
9
  /**
@@ -19,18 +19,18 @@ export class Pagination {
19
19
  * @param options An object providing values to initialize this instance.
20
20
  */
21
21
  constructor(options = {}) {
22
- this.currentPageIndex = options.currentPageIndex ?? 1;
22
+ this.currentPageIndex = options.currentPageIndex ?? 0;
23
23
  this.itemsPerPage = options.itemsPerPage ?? 25;
24
24
  this.totalItemCount = options.totalItemCount ?? 0;
25
25
  }
26
26
  /**
27
- * The one-based current page number.
27
+ * The current page index.
28
28
  */
29
29
  get currentPageIndex() {
30
30
  return this.#currentPageIndex;
31
31
  }
32
32
  set currentPageIndex(value) {
33
- this.#currentPageIndex = Math.max(1, value);
33
+ this.#currentPageIndex = Math.max(0, value);
34
34
  }
35
35
  /**
36
36
  * Value indicating whether a next page exists.
@@ -42,7 +42,7 @@ export class Pagination {
42
42
  * Value indicating whether a previous page exists.
43
43
  */
44
44
  get hasPreviousPage() {
45
- return this.#currentPageIndex > 1;
45
+ return this.#currentPageIndex > 0;
46
46
  }
47
47
  /**
48
48
  * The number of items per page.
@@ -54,10 +54,10 @@ export class Pagination {
54
54
  this.#itemsPerPage = Math.max(1, Math.min(1000, value));
55
55
  }
56
56
  /**
57
- * The one-based last page number.
57
+ * The last page index.
58
58
  */
59
59
  get lastPageIndex() {
60
- return this.#totalItemCount > 0 ? Math.ceil(this.#totalItemCount / this.#itemsPerPage) : 1;
60
+ return this.#totalItemCount > 0 ? Math.ceil(this.#totalItemCount / this.#itemsPerPage) - 1 : 0;
61
61
  }
62
62
  /**
63
63
  * The data limit.
@@ -69,13 +69,13 @@ export class Pagination {
69
69
  * The data offset.
70
70
  */
71
71
  get offset() {
72
- return (this.#currentPageIndex - 1) * this.#itemsPerPage;
72
+ return this.#currentPageIndex * this.#itemsPerPage;
73
73
  }
74
74
  /**
75
75
  * The search parameters corresponding to this object.
76
76
  */
77
77
  get searchParams() {
78
- return new URLSearchParams({ page: this.#currentPageIndex.toString(), perPage: this.#itemsPerPage.toString() });
78
+ return new URLSearchParams({ page: (this.#currentPageIndex + 1).toString(), perPage: this.#itemsPerPage.toString() });
79
79
  }
80
80
  /**
81
81
  * The total number of items.
@@ -93,7 +93,7 @@ export class Pagination {
93
93
  */
94
94
  static fromResponse(response) {
95
95
  return new this({
96
- currentPageIndex: Number(response.headers.get("X-Pagination-Current-Page") ?? "1"),
96
+ currentPageIndex: Number(response.headers.get("X-Pagination-Current-Page") ?? "1") - 1,
97
97
  itemsPerPage: Number(response.headers.get("X-Pagination-Per-Page") ?? "25"),
98
98
  totalItemCount: Number(response.headers.get("X-Pagination-Total-Count") ?? "0")
99
99
  });
@@ -22,4 +22,15 @@ export declare class KeyboardAccelerator extends HTMLElement {
22
22
  */
23
23
  disconnectedCallback(): void;
24
24
  }
25
+ /**
26
+ * Declaration merging.
27
+ */
28
+ declare global {
29
+ /**
30
+ * The map of HTML tag names.
31
+ */
32
+ interface HTMLElementTagNameMap {
33
+ "keyboard-accelerator": KeyboardAccelerator;
34
+ }
35
+ }
25
36
  //# sourceMappingURL=KeyboardAccelerator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"KeyboardAccelerator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/KeyboardAccelerator.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;;IAcnD;;OAEG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IACD,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,EAEpB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAItB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,EAK1B;IAED;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAuB5B"}
1
+ {"version":3,"file":"KeyboardAccelerator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/KeyboardAccelerator.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;;IAcnD;;OAEG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IACD,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,EAEpB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAItB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,EAK1B;IAED;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAuB5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,sBAAsB,EAAE,mBAAmB,CAAC;KAC5C;CACD"}
@@ -59,15 +59,15 @@ export class KeyboardAccelerator extends HTMLElement {
59
59
  if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement)
60
60
  return;
61
61
  const { modifiers } = this;
62
- if ((modifiers & KeyboardModifiers.Ctrl) != 0 && !event.ctrlKey)
62
+ if (!(modifiers & KeyboardModifiers.Ctrl) && event.ctrlKey)
63
63
  return;
64
- if ((modifiers & KeyboardModifiers.Shift) != 0 && !event.shiftKey)
64
+ if (!(modifiers & KeyboardModifiers.Shift) && event.shiftKey)
65
65
  return;
66
- if ((modifiers & KeyboardModifiers.Alt) != 0 && !event.altKey)
66
+ if (!(modifiers & KeyboardModifiers.Alt) && event.altKey)
67
67
  return;
68
- if ((modifiers & KeyboardModifiers.Meta) != 0 && !event.metaKey)
68
+ if (!(modifiers & KeyboardModifiers.Meta) && event.metaKey)
69
69
  return;
70
70
  event.preventDefault();
71
- this.firstElementChild.click();
71
+ this.firstElementChild?.click();
72
72
  };
73
73
  }
@@ -17,7 +17,7 @@ export class MenuActivator extends HTMLElement {
17
17
  anchor.classList.remove("active");
18
18
  else {
19
19
  anchor.classList.add("active");
20
- anchor.closest(".nav-item.dropdown")?.querySelector(".nav-link")?.classList.add("active");
20
+ anchor.closest(".dropdown")?.querySelector('[data-bs-toggle="dropdown"]')?.classList.add("active");
21
21
  }
22
22
  }
23
23
  }
@@ -3,10 +3,6 @@
3
3
  */
4
4
  export declare class OfflineIndicator extends HTMLElement {
5
5
  #private;
6
- /**
7
- * Creates a new offline indicator.
8
- */
9
- constructor();
10
6
  /**
11
7
  * Method invoked when this component is connected.
12
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"OfflineIndicator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/OfflineIndicator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;;IAEhD;;OAEG;;IAaH;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAS5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,gBAAgB,CAAC;KACtC;CACD"}
1
+ {"version":3,"file":"OfflineIndicator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/OfflineIndicator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;;IAShD;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAKzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAS5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,gBAAgB,CAAC;KACtC;CACD"}
@@ -2,13 +2,6 @@
2
2
  * A component that shows up when the network is unavailable, and hides when connectivity is restored.
3
3
  */
4
4
  export class OfflineIndicator extends HTMLElement {
5
- /**
6
- * Creates a new offline indicator.
7
- */
8
- constructor() {
9
- super();
10
- this.#updateHiddenState();
11
- }
12
5
  /**
13
6
  * Registers the component.
14
7
  */
@@ -19,6 +12,7 @@ export class OfflineIndicator extends HTMLElement {
19
12
  * Method invoked when this component is connected.
20
13
  */
21
14
  connectedCallback() {
15
+ this.#updateHiddenState();
22
16
  for (const event of ["online", "offline"])
23
17
  addEventListener(event, this.#updateHiddenState);
24
18
  }
@@ -4,7 +4,7 @@ import { StorageArea } from "../StorageArea.js";
4
4
  */
5
5
  export declare class TabActivator extends HTMLElement {
6
6
  /**
7
- * The one-based index of the active tab.
7
+ * The index of the active tab.
8
8
  */
9
9
  get activeTabIndex(): number;
10
10
  set activeTabIndex(value: number);
@@ -11,14 +11,14 @@ export class TabActivator extends HTMLElement {
11
11
  customElements.define("tab-activator", this);
12
12
  }
13
13
  /**
14
- * The one-based index of the active tab.
14
+ * The index of the active tab.
15
15
  */
16
16
  get activeTabIndex() {
17
- const index = Number.parseInt(this.storage.getItem(this.storageKey) ?? "1");
18
- return Math.max(1, Math.min(this.tabs.length, Number.isNaN(index) ? 1 : index));
17
+ const index = Number(this.storage.getItem(this.storageKey) ?? "1");
18
+ return Math.max(0, Math.min(this.tabs.length, Number.isNaN(index) ? 0 : index - 1));
19
19
  }
20
20
  set activeTabIndex(value) {
21
- this.storage.setItem(this.storageKey, value.toString());
21
+ this.storage.setItem(this.storageKey, (value + 1).toString());
22
22
  }
23
23
  /**
24
24
  * The storage object corresponding to the current {@link storageArea}.
@@ -50,15 +50,15 @@ export class TabActivator extends HTMLElement {
50
50
  * The tab list.
51
51
  */
52
52
  get tabs() {
53
- return this.querySelectorAll(".nav-tabs button");
53
+ return this.querySelectorAll('[data-bs-toggle="tab"]');
54
54
  }
55
55
  /**
56
56
  * Method invoked when this component is connected.
57
57
  */
58
58
  connectedCallback() {
59
59
  const { activeTabIndex, tabs } = this;
60
- for (let index = 1; index <= tabs.length; index++) {
61
- const tab = tabs.item(index - 1);
60
+ for (let index = 0; index < tabs.length - 1; index++) {
61
+ const tab = tabs.item(index);
62
62
  tab.addEventListener("click", () => this.activeTabIndex = index);
63
63
  if (index == activeTabIndex)
64
64
  Tab.getOrCreateInstance(tab).show();
@@ -9,6 +9,10 @@ export declare class ThemeDropdown extends HTMLElement {
9
9
  * The list of observed attributes.
10
10
  */
11
11
  static readonly observedAttributes: string[];
12
+ /**
13
+ * Creates a new theme dropdown.
14
+ */
15
+ constructor();
12
16
  /**
13
17
  * The alignment of the dropdown menu.
14
18
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ThemeDropdown.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/ThemeDropdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAU,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAElD;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAsC;IAcxE;;OAEG;IACH,IAAI,SAAS,IAAI,aAAa,CAG7B;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,aAAa,EAEjC;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,QAAQ,CAGvB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAG3B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAGvB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAwB/F;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAQzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAuB5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,aAAa,CAAC;KAChC;CACD"}
1
+ {"version":3,"file":"ThemeDropdown.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/ThemeDropdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAU,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAElD;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAsC;IAOxE;;OAEG;;IAaH;;OAEG;IACH,IAAI,SAAS,IAAI,aAAa,CAG7B;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,aAAa,EAEjC;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,QAAQ,CAGvB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAG3B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAGvB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAwB/F;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAsB5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,aAAa,CAAC;KAChC;CACD"}
@@ -12,6 +12,14 @@ export class ThemeDropdown extends HTMLElement {
12
12
  * The media query used to check the application theme.
13
13
  */
14
14
  #mediaQuery = matchMedia("(prefers-color-scheme: dark)");
15
+ /**
16
+ * Creates a new theme dropdown.
17
+ */
18
+ constructor() {
19
+ super();
20
+ for (const button of this.querySelectorAll("button"))
21
+ button.addEventListener("click", this.#setTheme);
22
+ }
15
23
  /**
16
24
  * Registers the component.
17
25
  */
@@ -95,19 +103,15 @@ export class ThemeDropdown extends HTMLElement {
95
103
  * Method invoked when this component is connected.
96
104
  */
97
105
  connectedCallback() {
98
- for (const button of this.querySelectorAll("button"))
99
- button.addEventListener("click", this.#setTheme);
100
- this.#mediaQuery.addEventListener("change", this.#applyTheme);
101
106
  const appTheme = localStorage.getItem(this.storageKey);
102
107
  if (appTheme)
103
108
  this.setAttribute("apptheme", appTheme);
109
+ this.#mediaQuery.addEventListener("change", this.#applyTheme);
104
110
  }
105
111
  /**
106
112
  * Method invoked when this component is disconnected.
107
113
  */
108
114
  disconnectedCallback() {
109
- for (const button of this.querySelectorAll("button"))
110
- button.removeEventListener("click", this.#setTheme);
111
115
  this.#mediaQuery.removeEventListener("change", this.#applyTheme);
112
116
  }
113
117
  /**
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Creates a document fragment from the specified HTML string.
3
+ * @param childContent The HTML string providing the child content.
4
+ * @returns The document fragment corresponding to the specified HTML string.
5
+ */
6
+ export declare function createDocumentFragment(childContent: string): DocumentFragment;
7
+ /**
8
+ * Returns a promise that resolves when the specified element has finished all its animations.
9
+ * @param element The target element.
10
+ * @returns The element animations.
11
+ */
12
+ export declare function waitForAnimations(element: Element): Promise<Array<PromiseSettledResult<Animation>>>;
13
+ //# sourceMappingURL=ElementExtensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ElementExtensions.d.ts","sourceRoot":"","sources":["../../src/Client/UI/ElementExtensions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB,CAI7E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC,CAEnG"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Creates a document fragment from the specified HTML string.
3
+ * @param childContent The HTML string providing the child content.
4
+ * @returns The document fragment corresponding to the specified HTML string.
5
+ */
6
+ export function createDocumentFragment(childContent) {
7
+ const template = document.createElement("template");
8
+ template.innerHTML = childContent;
9
+ return template.content;
10
+ }
11
+ /**
12
+ * Returns a promise that resolves when the specified element has finished all its animations.
13
+ * @param element The target element.
14
+ * @returns The element animations.
15
+ */
16
+ export function waitForAnimations(element) {
17
+ return Promise.allSettled(element.getAnimations().map(animation => animation.finished));
18
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Defines the size of a component.
3
+ */
4
+ export declare const Size: Readonly<{
5
+ /**
6
+ * An extra small size.
7
+ */
8
+ ExtraSmall: "xs";
9
+ /**
10
+ * A small size.
11
+ */
12
+ Small: "sm";
13
+ /**
14
+ * A medium size.
15
+ */
16
+ Medium: "md";
17
+ /**
18
+ * A large size.
19
+ */
20
+ Large: "lg";
21
+ /**
22
+ * An extra large size.
23
+ */
24
+ ExtraLarge: "xl";
25
+ /**
26
+ * An extra extra large size.
27
+ */
28
+ ExtraExtraLarge: "xxl";
29
+ }>;
30
+ /**
31
+ * Defines the size of a component.
32
+ */
33
+ export type Size = typeof Size[keyof typeof Size];
34
+ //# sourceMappingURL=Size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Size.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Size.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,IAAI;IAEhB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC"}
package/lib/UI/Size.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Defines the size of a component.
3
+ */
4
+ export const Size = Object.freeze({
5
+ /**
6
+ * An extra small size.
7
+ */
8
+ ExtraSmall: "xs",
9
+ /**
10
+ * A small size.
11
+ */
12
+ Small: "sm",
13
+ /**
14
+ * A medium size.
15
+ */
16
+ Medium: "md",
17
+ /**
18
+ * A large size.
19
+ */
20
+ Large: "lg",
21
+ /**
22
+ * An extra large size.
23
+ */
24
+ ExtraLarge: "xl",
25
+ /**
26
+ * An extra extra large size.
27
+ */
28
+ ExtraExtraLarge: "xxl"
29
+ });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Defines tone variants.
3
+ */
4
+ export declare const Variant: Readonly<{
5
+ /**
6
+ * A dark variant.
7
+ */
8
+ Dark: "dark";
9
+ /**
10
+ * A light variant.
11
+ */
12
+ Light: "light";
13
+ /**
14
+ * A primary variant.
15
+ */
16
+ Primary: "primary";
17
+ /**
18
+ * A secondary variant.
19
+ */
20
+ Secondary: "secondary";
21
+ }>;
22
+ /**
23
+ * Defines tone variants.
24
+ */
25
+ export type Variant = typeof Variant[keyof typeof Variant];
26
+ //# sourceMappingURL=Variant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Variant.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Variant.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,OAAO;IAEnB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Defines tone variants.
3
+ */
4
+ export const Variant = Object.freeze({
5
+ /**
6
+ * A dark variant.
7
+ */
8
+ Dark: "dark",
9
+ /**
10
+ * A light variant.
11
+ */
12
+ Light: "light",
13
+ /**
14
+ * A primary variant.
15
+ */
16
+ Primary: "primary",
17
+ /**
18
+ * A secondary variant.
19
+ */
20
+ Secondary: "secondary"
21
+ });
@@ -27,7 +27,7 @@ export class ViewportScroller {
27
27
  const navbar = document.body.querySelector(".navbar");
28
28
  this.#scrollOffset += (navbar?.offsetHeight ?? 0);
29
29
  }
30
- const actionBar = document.body.querySelector("action-bar, .action-bar");
30
+ const actionBar = document.body.querySelector("action-bar");
31
31
  return this.#scrollOffset + (actionBar?.offsetHeight ?? 0);
32
32
  }
33
33
  /**
package/package.json CHANGED
@@ -7,23 +7,23 @@
7
7
  "name": "@cedx/base",
8
8
  "repository": "cedx/base",
9
9
  "type": "module",
10
- "version": "0.10.0",
10
+ "version": "0.11.0",
11
11
  "devDependencies": {
12
- "@playwright/browser-chromium": "^1.54.2",
12
+ "@playwright/browser-chromium": "^1.55.0",
13
13
  "@types/bootstrap": "^5.2.10",
14
14
  "@types/chai": "^5.2.2",
15
15
  "@types/mocha": "^10.0.10",
16
16
  "@types/node": "^24.3.0",
17
17
  "@types/serve-handler": "^6.1.4",
18
- "chai": "^5.2.1",
18
+ "chai": "^6.0.0",
19
19
  "esbuild": "^0.25.9",
20
20
  "globals": "^16.3.0",
21
21
  "mocha": "^11.7.1",
22
- "playwright": "^1.54.2",
22
+ "playwright": "^1.55.0",
23
23
  "serve-handler": "^6.1.6",
24
24
  "typedoc": "^0.28.10",
25
25
  "typescript": "^5.9.2",
26
- "typescript-eslint": "^8.39.1"
26
+ "typescript-eslint": "^8.40.0"
27
27
  },
28
28
  "engines": {
29
29
  "node": ">=24.0.0"
@@ -4,7 +4,7 @@
4
4
  export class Pagination {
5
5
 
6
6
  /**
7
- * The one-based current page number.
7
+ * The current page index.
8
8
  */
9
9
  #currentPageIndex!: number;
10
10
 
@@ -23,19 +23,19 @@ export class Pagination {
23
23
  * @param options An object providing values to initialize this instance.
24
24
  */
25
25
  constructor(options: PaginationOptions = {}) {
26
- this.currentPageIndex = options.currentPageIndex ?? 1;
26
+ this.currentPageIndex = options.currentPageIndex ?? 0;
27
27
  this.itemsPerPage = options.itemsPerPage ?? 25;
28
28
  this.totalItemCount = options.totalItemCount ?? 0;
29
29
  }
30
30
 
31
31
  /**
32
- * The one-based current page number.
32
+ * The current page index.
33
33
  */
34
34
  get currentPageIndex(): number {
35
35
  return this.#currentPageIndex;
36
36
  }
37
37
  set currentPageIndex(value: number) {
38
- this.#currentPageIndex = Math.max(1, value);
38
+ this.#currentPageIndex = Math.max(0, value);
39
39
  }
40
40
 
41
41
  /**
@@ -49,7 +49,7 @@ export class Pagination {
49
49
  * Value indicating whether a previous page exists.
50
50
  */
51
51
  get hasPreviousPage(): boolean {
52
- return this.#currentPageIndex > 1;
52
+ return this.#currentPageIndex > 0;
53
53
  }
54
54
 
55
55
  /**
@@ -63,10 +63,10 @@ export class Pagination {
63
63
  }
64
64
 
65
65
  /**
66
- * The one-based last page number.
66
+ * The last page index.
67
67
  */
68
68
  get lastPageIndex(): number {
69
- return this.#totalItemCount > 0 ? Math.ceil(this.#totalItemCount / this.#itemsPerPage) : 1;
69
+ return this.#totalItemCount > 0 ? Math.ceil(this.#totalItemCount / this.#itemsPerPage) - 1 : 0;
70
70
  }
71
71
 
72
72
  /**
@@ -80,14 +80,14 @@ export class Pagination {
80
80
  * The data offset.
81
81
  */
82
82
  get offset(): number {
83
- return (this.#currentPageIndex - 1) * this.#itemsPerPage;
83
+ return this.#currentPageIndex * this.#itemsPerPage;
84
84
  }
85
85
 
86
86
  /**
87
87
  * The search parameters corresponding to this object.
88
88
  */
89
89
  get searchParams(): URLSearchParams {
90
- return new URLSearchParams({page: this.#currentPageIndex.toString(), perPage: this.#itemsPerPage.toString()});
90
+ return new URLSearchParams({page: (this.#currentPageIndex + 1).toString(), perPage: this.#itemsPerPage.toString()});
91
91
  }
92
92
 
93
93
  /**
@@ -107,7 +107,7 @@ export class Pagination {
107
107
  */
108
108
  static fromResponse(response: Response): Pagination {
109
109
  return new this({
110
- currentPageIndex: Number(response.headers.get("X-Pagination-Current-Page") ?? "1"),
110
+ currentPageIndex: Number(response.headers.get("X-Pagination-Current-Page") ?? "1") - 1,
111
111
  itemsPerPage: Number(response.headers.get("X-Pagination-Per-Page") ?? "25"),
112
112
  totalItemCount: Number(response.headers.get("X-Pagination-Total-Count") ?? "0")
113
113
  });
@@ -120,7 +120,7 @@ export class Pagination {
120
120
  export type PaginationOptions = Partial<{
121
121
 
122
122
  /**
123
- * The one-based current page number.
123
+ * The current page index.
124
124
  */
125
125
  currentPageIndex: number;
126
126
 
@@ -67,12 +67,25 @@ export class KeyboardAccelerator extends HTMLElement {
67
67
  if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement) return;
68
68
 
69
69
  const {modifiers} = this;
70
- if ((modifiers & KeyboardModifiers.Ctrl) != 0 && !event.ctrlKey) return;
71
- if ((modifiers & KeyboardModifiers.Shift) != 0 && !event.shiftKey) return;
72
- if ((modifiers & KeyboardModifiers.Alt) != 0 && !event.altKey) return;
73
- if ((modifiers & KeyboardModifiers.Meta) != 0 && !event.metaKey) return;
70
+ if (!(modifiers & KeyboardModifiers.Ctrl) && event.ctrlKey) return;
71
+ if (!(modifiers & KeyboardModifiers.Shift) && event.shiftKey) return;
72
+ if (!(modifiers & KeyboardModifiers.Alt) && event.altKey) return;
73
+ if (!(modifiers & KeyboardModifiers.Meta) && event.metaKey) return;
74
74
 
75
75
  event.preventDefault();
76
- (this.firstElementChild as HTMLElement).click();
76
+ (this.firstElementChild as HTMLElement|null)?.click();
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Declaration merging.
82
+ */
83
+ declare global {
84
+
85
+ /**
86
+ * The map of HTML tag names.
87
+ */
88
+ interface HTMLElementTagNameMap {
89
+ "keyboard-accelerator": KeyboardAccelerator;
77
90
  }
78
91
  }
@@ -18,7 +18,7 @@ export class MenuActivator extends HTMLElement {
18
18
  if (anchor.href != location.href) anchor.classList.remove("active");
19
19
  else {
20
20
  anchor.classList.add("active");
21
- anchor.closest(".nav-item.dropdown")?.querySelector(".nav-link")?.classList.add("active");
21
+ anchor.closest(".dropdown")?.querySelector('[data-bs-toggle="dropdown"]')?.classList.add("active");
22
22
  }
23
23
  }
24
24
  }
@@ -0,0 +1,242 @@
1
+ import {Context, getIcon} from "../Context.js";
2
+ import {Variant} from "../Variant.js";
3
+
4
+ /**
5
+ * Specifies the return value of a message box.
6
+ */
7
+ export const MessageBoxResult = Object.freeze({
8
+
9
+ /**
10
+ * The message box does not return any value.
11
+ */
12
+ None: "",
13
+
14
+ /**
15
+ * The return value of the message box is "OK".
16
+ */
17
+ OK: "OK",
18
+
19
+ /**
20
+ * The return value of the message box is "Cancel".
21
+ */
22
+ Cancel: "Cancel"
23
+ });
24
+
25
+ /**
26
+ * Specifies the return value of a message box.
27
+ */
28
+ export type MessageBoxResult = typeof MessageBoxResult[keyof typeof MessageBoxResult];
29
+
30
+ /**
31
+ * Displays a message window, also known as dialog box, which presents a message to the user.
32
+ */
33
+ export class MessageBox extends HTMLElement {
34
+
35
+ /**
36
+ * Value indicating whether to vertically center this message box.
37
+ */
38
+ @property({type: Boolean}) centered = false;
39
+
40
+ /**
41
+ * The buttons displayed in the footer.
42
+ */
43
+ @state() private buttons: MessageBoxButton[] = [];
44
+
45
+ /**
46
+ * The title displayed in the header.
47
+ */
48
+ @state() private caption = "";
49
+
50
+ /**
51
+ * The message displayed in the body.
52
+ */
53
+ @state() private content: TemplateResult = html``;
54
+
55
+ /**
56
+ * A contextual modifier.
57
+ */
58
+ @state() private context: Context|null = null;
59
+
60
+ /**
61
+ * The icon displayed next to the body.
62
+ */
63
+ @state() private icon = "";
64
+
65
+ /**
66
+ * The root element.
67
+ */
68
+ @query("dialog", true) private readonly root!: HTMLDialogElement;
69
+
70
+ /**
71
+ * The function invoked to return the dialog box result.
72
+ */
73
+ #resolve: (value: string) => void = () => { /* Noop */ };
74
+
75
+ /**
76
+ * Opens an alert dialog with the specified message and an "OK" button.
77
+ * @param caption The title displayed in the header.
78
+ * @param message The message to show.
79
+ * @param options The message box options.
80
+ * @returns Resolves with the value of the clicked button.
81
+ */
82
+ alert(caption: string, message: TemplateResult, options: MessageBoxOptions = {}): Promise<string> {
83
+ const context = options.context ?? Context.Warning;
84
+ return this.show(message, {
85
+ buttons: options.buttons ?? [{label: "OK", value: MessageBoxResult.OK}],
86
+ caption,
87
+ context,
88
+ icon: options.icon ?? getIcon(context)
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Closes the message box.
94
+ * @param result The message box result.
95
+ */
96
+ close(result: MessageBoxResult = MessageBoxResult.None): void {
97
+ this.root.close(result);
98
+ }
99
+
100
+ /**
101
+ * Opens a confirmation dialog with the specified message and two buttons, "OK" and "Cancel".
102
+ * @param caption The title displayed in the header.
103
+ * @param message The message to show.
104
+ * @param options The message box options.
105
+ * @returns Resolves with the value of the clicked button.
106
+ */
107
+ confirm(caption: string, message: TemplateResult, options: MessageBoxOptions = {}): Promise<string> {
108
+ const context = options.context ?? Context.Warning;
109
+ return this.show(message, {
110
+ caption,
111
+ context,
112
+ icon: options.icon ?? getIcon(context),
113
+ buttons: options.buttons ?? [
114
+ {label: "OK", value: MessageBoxResult.OK},
115
+ {label: "Annuler", value: MessageBoxResult.Cancel, variant: Variant.Secondary}
116
+ ]
117
+ });
118
+ }
119
+
120
+ /**
121
+ * Opens a modal dialog with the specified message and options.
122
+ * @param message The message to show.
123
+ * @param options The message box options.
124
+ * @returns Resolves with the value of the clicked button.
125
+ */
126
+ show(message: TemplateResult, options: MessageBoxOptions = {}): Promise<string> {
127
+ this.buttons = options.buttons ?? [];
128
+ this.caption = options.caption ?? "";
129
+ this.content = message;
130
+ this.context = options.context ?? null;
131
+ this.icon = options.icon ?? "";
132
+
133
+ this.root.returnValue = MessageBoxResult.None;
134
+ this.root.showModal();
135
+ this.root.querySelector<HTMLButtonElement>(".btn-close")?.blur();
136
+
137
+ const {promise, resolve} = Promise.withResolvers<string>();
138
+ this.#resolve = resolve;
139
+ return promise;
140
+ }
141
+
142
+ /**
143
+ * Renders this component.
144
+ * @returns The view template.
145
+ */
146
+ protected override render(): TemplateResult {
147
+ const centered = classMap({"modal-dialog-centered": this.centered});
148
+ return html`
149
+ <dialog class="modal modal-dialog modal-dialog-scrollable ${centered}" @click=${this.#onDialogClick} @close=${this.#onDialogClose}>
150
+ <form class="modal-content" method="dialog">
151
+ <div class="modal-header user-select-none">
152
+ ${when(this.caption, () => html`<h1 class="modal-title fs-5">${this.caption}</h1>`)}
153
+ <button class="btn-close"></button>
154
+ </div>
155
+ <div class="modal-body d-flex">
156
+ ${when(this.icon, () => html`
157
+ <i class="icon icon-fill fs-1 fw-semibold me-2 ${classMap({[`text-${this.context}`]: this.context ?? ""})}">${this.icon}</i>
158
+ `)}
159
+ <div class="flex-grow-1">${this.content}</div>
160
+ </div>
161
+ ${when(this.buttons.length, () => html`
162
+ <div class="modal-footer user-select-none">
163
+ ${this.buttons.map(button => html`
164
+ <button class="btn btn-${button.variant ?? Variant.Primary}" value=${button.value ?? MessageBoxResult.None}>
165
+ ${when(button.icon, () => html`<i class="icon icon-fill ${classMap({"me-1": button.label ?? ""})}">${button.icon}</i>`)}
166
+ ${button.label}
167
+ </button>
168
+ `)}
169
+ </div>
170
+ `)}
171
+ </form>
172
+ </dialog>
173
+ `;
174
+ }
175
+
176
+ /**
177
+ * Handles the `click` event.
178
+ * @param event The dispatched event.
179
+ */
180
+ #onDialogClick(event: Event): void {
181
+ if (event.target == this.root) this.close();
182
+ }
183
+
184
+ /**
185
+ * Handles the `close` event.
186
+ */
187
+ #onDialogClose(): void {
188
+ this.#resolve(this.root.returnValue);
189
+ }
190
+ }
191
+
192
+ /**
193
+ * A message box button.
194
+ */
195
+ export type MessageBoxButton = Partial<{
196
+
197
+ /**
198
+ * The button icon.
199
+ */
200
+ icon: string;
201
+
202
+ /**
203
+ * The button label.
204
+ */
205
+ label: string;
206
+
207
+ /**
208
+ * The button value.
209
+ */
210
+ value: string;
211
+
212
+ /**
213
+ * A tone variant.
214
+ */
215
+ variant: Context|Variant;
216
+ }>;
217
+
218
+ /**
219
+ * Defines the options of a {@link MessageBox} instance.
220
+ */
221
+ export type MessageBoxOptions = Partial<{
222
+
223
+ /**
224
+ * The buttons displayed in the footer.
225
+ */
226
+ buttons: MessageBoxButton[];
227
+
228
+ /**
229
+ * The title displayed in the header.
230
+ */
231
+ caption: string;
232
+
233
+ /**
234
+ * A contextual modifier.
235
+ */
236
+ context: Context;
237
+
238
+ /**
239
+ * The icon displayed next to the body.
240
+ */
241
+ icon: string;
242
+ }>;
@@ -3,14 +3,6 @@
3
3
  */
4
4
  export class OfflineIndicator extends HTMLElement {
5
5
 
6
- /**
7
- * Creates a new offline indicator.
8
- */
9
- constructor() {
10
- super();
11
- this.#updateHiddenState();
12
- }
13
-
14
6
  /**
15
7
  * Registers the component.
16
8
  */
@@ -22,6 +14,7 @@ export class OfflineIndicator extends HTMLElement {
22
14
  * Method invoked when this component is connected.
23
15
  */
24
16
  connectedCallback(): void {
17
+ this.#updateHiddenState();
25
18
  for (const event of ["online", "offline"]) addEventListener(event, this.#updateHiddenState);
26
19
  }
27
20
 
@@ -14,14 +14,14 @@ export class TabActivator extends HTMLElement {
14
14
  }
15
15
 
16
16
  /**
17
- * The one-based index of the active tab.
17
+ * The index of the active tab.
18
18
  */
19
19
  get activeTabIndex(): number {
20
- const index = Number.parseInt(this.storage.getItem(this.storageKey) ?? "1");
21
- return Math.max(1, Math.min(this.tabs.length, Number.isNaN(index) ? 1 : index));
20
+ const index = Number(this.storage.getItem(this.storageKey) ?? "1");
21
+ return Math.max(0, Math.min(this.tabs.length, Number.isNaN(index) ? 0 : index - 1));
22
22
  }
23
23
  set activeTabIndex(value: number) {
24
- this.storage.setItem(this.storageKey, value.toString());
24
+ this.storage.setItem(this.storageKey, (value + 1).toString());
25
25
  }
26
26
 
27
27
  /**
@@ -57,7 +57,7 @@ export class TabActivator extends HTMLElement {
57
57
  * The tab list.
58
58
  */
59
59
  get tabs(): NodeListOf<HTMLButtonElement> {
60
- return this.querySelectorAll(".nav-tabs button");
60
+ return this.querySelectorAll('[data-bs-toggle="tab"]');
61
61
  }
62
62
 
63
63
  /**
@@ -65,8 +65,8 @@ export class TabActivator extends HTMLElement {
65
65
  */
66
66
  connectedCallback(): void {
67
67
  const {activeTabIndex, tabs} = this;
68
- for (let index = 1; index <= tabs.length; index++) {
69
- const tab = tabs.item(index - 1);
68
+ for (let index = 0; index < tabs.length - 1; index++) {
69
+ const tab = tabs.item(index);
70
70
  tab.addEventListener("click", () => this.activeTabIndex = index);
71
71
  if (index == activeTabIndex) Tab.getOrCreateInstance(tab).show();
72
72
  }
@@ -16,6 +16,14 @@ export class ThemeDropdown extends HTMLElement {
16
16
  */
17
17
  readonly #mediaQuery = matchMedia("(prefers-color-scheme: dark)");
18
18
 
19
+ /**
20
+ * Creates a new theme dropdown.
21
+ */
22
+ constructor() {
23
+ super();
24
+ for (const button of this.querySelectorAll("button")) button.addEventListener("click", this.#setTheme);
25
+ }
26
+
19
27
  /**
20
28
  * Registers the component.
21
29
  */
@@ -102,18 +110,15 @@ export class ThemeDropdown extends HTMLElement {
102
110
  * Method invoked when this component is connected.
103
111
  */
104
112
  connectedCallback(): void {
105
- for (const button of this.querySelectorAll("button")) button.addEventListener("click", this.#setTheme);
106
- this.#mediaQuery.addEventListener("change", this.#applyTheme);
107
-
108
113
  const appTheme = localStorage.getItem(this.storageKey) as AppTheme|null;
109
114
  if (appTheme) this.setAttribute("apptheme", appTheme);
115
+ this.#mediaQuery.addEventListener("change", this.#applyTheme);
110
116
  }
111
117
 
112
118
  /**
113
119
  * Method invoked when this component is disconnected.
114
120
  */
115
121
  disconnectedCallback(): void {
116
- for (const button of this.querySelectorAll("button")) button.removeEventListener("click", this.#setTheme);
117
122
  this.#mediaQuery.removeEventListener("change", this.#applyTheme);
118
123
  }
119
124
 
File without changes
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Creates a document fragment from the specified HTML string.
3
+ * @param childContent The HTML string providing the child content.
4
+ * @returns The document fragment corresponding to the specified HTML string.
5
+ */
6
+ export function createDocumentFragment(childContent: string): DocumentFragment {
7
+ const template = document.createElement("template");
8
+ template.innerHTML = childContent;
9
+ return template.content;
10
+ }
11
+
12
+ /**
13
+ * Returns a promise that resolves when the specified element has finished all its animations.
14
+ * @param element The target element.
15
+ * @returns The element animations.
16
+ */
17
+ export function waitForAnimations(element: Element): Promise<Array<PromiseSettledResult<Animation>>> {
18
+ return Promise.allSettled(element.getAnimations().map(animation => animation.finished));
19
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Defines the size of a component.
3
+ */
4
+ export const Size = Object.freeze({
5
+
6
+ /**
7
+ * An extra small size.
8
+ */
9
+ ExtraSmall: "xs",
10
+
11
+ /**
12
+ * A small size.
13
+ */
14
+ Small: "sm",
15
+
16
+ /**
17
+ * A medium size.
18
+ */
19
+ Medium: "md",
20
+
21
+ /**
22
+ * A large size.
23
+ */
24
+ Large: "lg",
25
+
26
+ /**
27
+ * An extra large size.
28
+ */
29
+ ExtraLarge: "xl",
30
+
31
+ /**
32
+ * An extra extra large size.
33
+ */
34
+ ExtraExtraLarge: "xxl"
35
+ });
36
+
37
+ /**
38
+ * Defines the size of a component.
39
+ */
40
+ export type Size = typeof Size[keyof typeof Size];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Defines tone variants.
3
+ */
4
+ export const Variant = Object.freeze({
5
+
6
+ /**
7
+ * A dark variant.
8
+ */
9
+ Dark: "dark",
10
+
11
+ /**
12
+ * A light variant.
13
+ */
14
+ Light: "light",
15
+
16
+ /**
17
+ * A primary variant.
18
+ */
19
+ Primary: "primary",
20
+
21
+ /**
22
+ * A secondary variant.
23
+ */
24
+ Secondary: "secondary"
25
+ });
26
+
27
+ /**
28
+ * Defines tone variants.
29
+ */
30
+ export type Variant = typeof Variant[keyof typeof Variant];
@@ -44,7 +44,7 @@ export class ViewportScroller {
44
44
  this.#scrollOffset += (navbar?.offsetHeight ?? 0);
45
45
  }
46
46
 
47
- const actionBar = document.body.querySelector<HTMLElement>("action-bar, .action-bar");
47
+ const actionBar = document.body.querySelector<HTMLElement>("action-bar");
48
48
  return this.#scrollOffset + (actionBar?.offsetHeight ?? 0);
49
49
  }
50
50