@cedx/base 0.9.0 → 0.10.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 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.9.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.10.1/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).
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Represents a shortcut key associated with an element.
3
+ */
4
+ export declare class KeyboardAccelerator extends HTMLElement {
5
+ #private;
6
+ /**
7
+ * Identifies the key for the keyboard accelerator.
8
+ */
9
+ get key(): string;
10
+ set key(value: string);
11
+ /**
12
+ * Identifies the modifiers for the keyboard accelerator.
13
+ */
14
+ get modifiers(): number;
15
+ set modifiers(value: number);
16
+ /**
17
+ * Method invoked when this component is connected.
18
+ */
19
+ connectedCallback(): void;
20
+ /**
21
+ * Method invoked when this component is disconnected.
22
+ */
23
+ disconnectedCallback(): void;
24
+ }
25
+ //# sourceMappingURL=KeyboardAccelerator.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,73 @@
1
+ import { KeyboardModifiers } from "../KeyboardModifiers.js";
2
+ /**
3
+ * Represents a shortcut key associated with an element.
4
+ */
5
+ export class KeyboardAccelerator extends HTMLElement {
6
+ /**
7
+ * The mapping between the modifier names and their values.
8
+ */
9
+ static #modifiers = new Map(Object.entries(KeyboardModifiers).filter(([key]) => key != "None"));
10
+ /**
11
+ * Registers the component.
12
+ */
13
+ static {
14
+ customElements.define("keyboard-accelerator", this);
15
+ }
16
+ /**
17
+ * Identifies the key for the keyboard accelerator.
18
+ */
19
+ get key() {
20
+ return (this.getAttribute("key") ?? "").trim();
21
+ }
22
+ set key(value) {
23
+ this.setAttribute("key", value);
24
+ }
25
+ /**
26
+ * Identifies the modifiers for the keyboard accelerator.
27
+ */
28
+ get modifiers() {
29
+ return (this.getAttribute("modifiers") ?? "").split(",")
30
+ .map(value => value.trim())
31
+ .reduce((modifiers, value) => modifiers | (KeyboardAccelerator.#modifiers.get(value) ?? 0), KeyboardModifiers.None);
32
+ }
33
+ set modifiers(value) {
34
+ this.setAttribute("modifiers", KeyboardAccelerator.#modifiers.entries()
35
+ .filter(([, flag]) => (value & flag) != 0)
36
+ .map(([key]) => key)
37
+ .toArray().join(", "));
38
+ }
39
+ /**
40
+ * Method invoked when this component is connected.
41
+ */
42
+ connectedCallback() {
43
+ addEventListener("keyup", this.#activateChildContent, { capture: true });
44
+ }
45
+ /**
46
+ * Method invoked when this component is disconnected.
47
+ */
48
+ disconnectedCallback() {
49
+ removeEventListener("keyup", this.#activateChildContent, { capture: true });
50
+ }
51
+ /**
52
+ * Activates the child content when the specified keyboard event designates the same key and modifiers as this keyboard accelerator.
53
+ * @param event The dispatched event.
54
+ */
55
+ #activateChildContent = event => {
56
+ if (event.key != this.key)
57
+ return;
58
+ const { activeElement } = document;
59
+ if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement)
60
+ return;
61
+ const { modifiers } = this;
62
+ if (!(modifiers & KeyboardModifiers.Ctrl) && event.ctrlKey)
63
+ return;
64
+ if (!(modifiers & KeyboardModifiers.Shift) && event.shiftKey)
65
+ return;
66
+ if (!(modifiers & KeyboardModifiers.Alt) && event.altKey)
67
+ return;
68
+ if (!(modifiers & KeyboardModifiers.Meta) && event.metaKey)
69
+ return;
70
+ event.preventDefault();
71
+ this.firstElementChild.click();
72
+ };
73
+ }
@@ -3,14 +3,6 @@
3
3
  */
4
4
  export declare class LoadingIndicator extends HTMLElement {
5
5
  #private;
6
- /**
7
- * Hides this component.
8
- */
9
- hide(): void;
10
- /**
11
- * Shows this component.
12
- */
13
- show(): void;
14
6
  /**
15
7
  * Starts the loading indicator.
16
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingIndicator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/LoadingIndicator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;;IAchD;;OAEG;IACH,IAAI,IAAI,IAAI;IAKZ;;OAEG;IACH,IAAI,IAAI,IAAI;IAKZ;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;;OAGG;IACH,IAAI,CAAC,OAAO,GAAE;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAM,GAAG,IAAI;CAO3C;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,gBAAgB,CAAC;KACtC;CACD"}
1
+ {"version":3,"file":"LoadingIndicator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/LoadingIndicator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;;IAchD;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;;OAGG;IACH,IAAI,CAAC,OAAO,GAAE;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAM,GAAG,IAAI;CAO3C;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,gBAAgB,CAAC;KACtC;CACD"}
@@ -12,26 +12,12 @@ export class LoadingIndicator extends HTMLElement {
12
12
  static {
13
13
  customElements.define("loading-indicator", this);
14
14
  }
15
- /**
16
- * Hides this component.
17
- */
18
- hide() {
19
- this.hidden = true;
20
- document.body.classList.remove("loading");
21
- }
22
- /**
23
- * Shows this component.
24
- */
25
- show() {
26
- this.hidden = false;
27
- document.body.classList.add("loading");
28
- }
29
15
  /**
30
16
  * Starts the loading indicator.
31
17
  */
32
18
  start() {
33
19
  this.#requestCount++;
34
- this.show();
20
+ this.hidden = false;
35
21
  }
36
22
  /**
37
23
  * Stops the loading indicator.
@@ -41,7 +27,7 @@ export class LoadingIndicator extends HTMLElement {
41
27
  this.#requestCount--;
42
28
  if (options.force || this.#requestCount <= 0) {
43
29
  this.#requestCount = 0;
44
- this.hide();
30
+ this.hidden = true;
45
31
  }
46
32
  }
47
33
  }
@@ -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
  }
@@ -15,14 +15,6 @@ export declare class OfflineIndicator extends HTMLElement {
15
15
  * Method invoked when this component is disconnected.
16
16
  */
17
17
  disconnectedCallback(): void;
18
- /**
19
- * Hides this component.
20
- */
21
- hide(): void;
22
- /**
23
- * Shows this component.
24
- */
25
- show(): void;
26
18
  }
27
19
  /**
28
20
  * Declaration merging.
@@ -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;IAI5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,IAAI,IAAI,IAAI;CASZ;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;;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"}
@@ -29,18 +29,6 @@ export class OfflineIndicator extends HTMLElement {
29
29
  for (const event of ["online", "offline"])
30
30
  removeEventListener(event, this.#updateHiddenState);
31
31
  }
32
- /**
33
- * Hides this component.
34
- */
35
- hide() {
36
- this.hidden = true;
37
- }
38
- /**
39
- * Shows this component.
40
- */
41
- show() {
42
- this.hidden = false;
43
- }
44
32
  /**
45
33
  * Updates the hidden state of this component according to the {@link navigator.onLine} property.
46
34
  */
@@ -50,7 +50,7 @@ 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.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Enumerates modifier flags for keyboard accelerators.
3
+ */
4
+ export declare const KeyboardModifiers: Readonly<{
5
+ /**
6
+ * Indicates no modifier.
7
+ */
8
+ None: 0;
9
+ /**
10
+ * Indicates the `Control` modifier.
11
+ */
12
+ Ctrl: 1;
13
+ /**
14
+ * Indicates the `Shift` modifier.
15
+ */
16
+ Shift: 2;
17
+ /**
18
+ * Indicates the `Alt` modifier (`Option` key on macOS, `Menu` key on Windows).
19
+ */
20
+ Alt: 4;
21
+ /**
22
+ * Indicates the `Meta` modifier (`Command` key on macOS, `Windows` key on Windows).
23
+ */
24
+ Meta: 8;
25
+ }>;
26
+ //# sourceMappingURL=KeyboardModifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeyboardModifiers.d.ts","sourceRoot":"","sources":["../../src/Client/UI/KeyboardModifiers.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,iBAAiB;IAE7B;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Enumerates modifier flags for keyboard accelerators.
3
+ */
4
+ export const KeyboardModifiers = Object.freeze({
5
+ /**
6
+ * Indicates no modifier.
7
+ */
8
+ None: 0,
9
+ /**
10
+ * Indicates the `Control` modifier.
11
+ */
12
+ Ctrl: 1,
13
+ /**
14
+ * Indicates the `Shift` modifier.
15
+ */
16
+ Shift: 2,
17
+ /**
18
+ * Indicates the `Alt` modifier (`Option` key on macOS, `Menu` key on Windows).
19
+ */
20
+ Alt: 4,
21
+ /**
22
+ * Indicates the `Meta` modifier (`Command` key on macOS, `Windows` key on Windows).
23
+ */
24
+ Meta: 8
25
+ });
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "name": "@cedx/base",
8
8
  "repository": "cedx/base",
9
9
  "type": "module",
10
- "version": "0.9.0",
10
+ "version": "0.10.1",
11
11
  "devDependencies": {
12
12
  "@playwright/browser-chromium": "^1.54.2",
13
13
  "@types/bootstrap": "^5.2.10",
@@ -15,7 +15,7 @@
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": "^5.3.1",
19
19
  "esbuild": "^0.25.9",
20
20
  "globals": "^16.3.0",
21
21
  "mocha": "^11.7.1",
@@ -0,0 +1,78 @@
1
+ import {KeyboardModifiers} from "../KeyboardModifiers.js";
2
+
3
+ /**
4
+ * Represents a shortcut key associated with an element.
5
+ */
6
+ export class KeyboardAccelerator extends HTMLElement {
7
+
8
+ /**
9
+ * The mapping between the modifier names and their values.
10
+ */
11
+ static readonly #modifiers = new Map(Object.entries(KeyboardModifiers).filter(([key]) => key != "None"));
12
+
13
+ /**
14
+ * Registers the component.
15
+ */
16
+ static {
17
+ customElements.define("keyboard-accelerator", this);
18
+ }
19
+
20
+ /**
21
+ * Identifies the key for the keyboard accelerator.
22
+ */
23
+ get key(): string {
24
+ return (this.getAttribute("key") ?? "").trim();
25
+ }
26
+ set key(value: string) {
27
+ this.setAttribute("key", value);
28
+ }
29
+
30
+ /**
31
+ * Identifies the modifiers for the keyboard accelerator.
32
+ */
33
+ get modifiers(): number {
34
+ return (this.getAttribute("modifiers") ?? "").split(",")
35
+ .map(value => value.trim())
36
+ .reduce<number>((modifiers, value) => modifiers | (KeyboardAccelerator.#modifiers.get(value) ?? 0), KeyboardModifiers.None);
37
+ }
38
+ set modifiers(value: number) {
39
+ this.setAttribute("modifiers", KeyboardAccelerator.#modifiers.entries()
40
+ .filter(([, flag]) => (value & flag) != 0)
41
+ .map(([key]) => key)
42
+ .toArray().join(", "));
43
+ }
44
+
45
+ /**
46
+ * Method invoked when this component is connected.
47
+ */
48
+ connectedCallback(): void {
49
+ addEventListener("keyup", this.#activateChildContent, {capture: true});
50
+ }
51
+
52
+ /**
53
+ * Method invoked when this component is disconnected.
54
+ */
55
+ disconnectedCallback(): void {
56
+ removeEventListener("keyup", this.#activateChildContent, {capture: true});
57
+ }
58
+
59
+ /**
60
+ * Activates the child content when the specified keyboard event designates the same key and modifiers as this keyboard accelerator.
61
+ * @param event The dispatched event.
62
+ */
63
+ readonly #activateChildContent: (event: KeyboardEvent) => void = event => {
64
+ if (event.key != this.key) return;
65
+
66
+ const {activeElement} = document;
67
+ if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement) return;
68
+
69
+ const {modifiers} = this;
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
+
75
+ event.preventDefault();
76
+ (this.firstElementChild as HTMLElement).click();
77
+ }
78
+ }
@@ -15,28 +15,12 @@ export class LoadingIndicator extends HTMLElement {
15
15
  customElements.define("loading-indicator", this);
16
16
  }
17
17
 
18
- /**
19
- * Hides this component.
20
- */
21
- hide(): void {
22
- this.hidden = true;
23
- document.body.classList.remove("loading");
24
- }
25
-
26
- /**
27
- * Shows this component.
28
- */
29
- show(): void {
30
- this.hidden = false;
31
- document.body.classList.add("loading");
32
- }
33
-
34
18
  /**
35
19
  * Starts the loading indicator.
36
20
  */
37
21
  start(): void {
38
22
  this.#requestCount++;
39
- this.show();
23
+ this.hidden = false;
40
24
  }
41
25
 
42
26
  /**
@@ -47,7 +31,7 @@ export class LoadingIndicator extends HTMLElement {
47
31
  this.#requestCount--;
48
32
  if (options.force || this.#requestCount <= 0) {
49
33
  this.#requestCount = 0;
50
- this.hide();
34
+ this.hidden = true;
51
35
  }
52
36
  }
53
37
  }
@@ -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
  }
@@ -32,20 +32,6 @@ export class OfflineIndicator extends HTMLElement {
32
32
  for (const event of ["online", "offline"]) removeEventListener(event, this.#updateHiddenState);
33
33
  }
34
34
 
35
- /**
36
- * Hides this component.
37
- */
38
- hide(): void {
39
- this.hidden = true;
40
- }
41
-
42
- /**
43
- * Shows this component.
44
- */
45
- show(): void {
46
- this.hidden = false;
47
- }
48
-
49
35
  /**
50
36
  * Updates the hidden state of this component according to the {@link navigator.onLine} property.
51
37
  */
@@ -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
  /**
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Enumerates modifier flags for keyboard accelerators.
3
+ */
4
+ export const KeyboardModifiers = Object.freeze({
5
+
6
+ /**
7
+ * Indicates no modifier.
8
+ */
9
+ None: 0,
10
+
11
+ /**
12
+ * Indicates the `Control` modifier.
13
+ */
14
+ Ctrl: 1,
15
+
16
+ /**
17
+ * Indicates the `Shift` modifier.
18
+ */
19
+ Shift: 2,
20
+
21
+ /**
22
+ * Indicates the `Alt` modifier (`Option` key on macOS, `Menu` key on Windows).
23
+ */
24
+ Alt: 4,
25
+
26
+ /**
27
+ * Indicates the `Meta` modifier (`Command` key on macOS, `Windows` key on Windows).
28
+ */
29
+ Meta: 8
30
+ });