@cedx/base 0.36.2 → 0.37.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 (44) hide show
  1. package/lib/Htmx.d.ts +12 -0
  2. package/lib/Htmx.d.ts.map +1 -0
  3. package/lib/Htmx.js +2 -0
  4. package/lib/Signal.d.ts +16 -0
  5. package/lib/Signal.d.ts.map +1 -0
  6. package/lib/{UI/Signal.js → Signal.js} +5 -5
  7. package/lib/UI/Component.d.ts +3 -3
  8. package/lib/UI/Component.d.ts.map +1 -1
  9. package/lib/UI/Component.js +4 -4
  10. package/lib/UI/Components/BackButton.d.ts +1 -5
  11. package/lib/UI/Components/BackButton.d.ts.map +1 -1
  12. package/lib/UI/Components/BackButton.js +3 -10
  13. package/lib/UI/Components/DialogBox.js +3 -3
  14. package/lib/UI/Components/FullScreenToggler.d.ts +1 -5
  15. package/lib/UI/Components/FullScreenToggler.d.ts.map +1 -1
  16. package/lib/UI/Components/FullScreenToggler.js +15 -24
  17. package/lib/UI/Components/KeyboardAccelerator.d.ts.map +1 -1
  18. package/lib/UI/Components/KeyboardAccelerator.js +10 -9
  19. package/lib/UI/Components/LoadingIndicator.d.ts.map +1 -1
  20. package/lib/UI/Components/LoadingIndicator.js +1 -0
  21. package/lib/UI/Components/MenuActivator.d.ts.map +1 -1
  22. package/lib/UI/Components/MenuActivator.js +7 -7
  23. package/lib/UI/Components/OfflineIndicator.d.ts.map +1 -1
  24. package/lib/UI/Components/OfflineIndicator.js +6 -5
  25. package/lib/UI/Components/ThemeDropdown.d.ts.map +1 -1
  26. package/lib/UI/Components/ThemeDropdown.js +6 -5
  27. package/lib/UI/Components/Toast.d.ts.map +1 -1
  28. package/lib/UI/Components/Toast.js +11 -6
  29. package/package.json +5 -3
  30. package/src/Client/Htmx.ts +13 -0
  31. package/src/Client/Signal.ts +18 -0
  32. package/src/Client/UI/Component.ts +4 -4
  33. package/src/Client/UI/Components/BackButton.ts +3 -11
  34. package/src/Client/UI/Components/DialogBox.ts +1 -1
  35. package/src/Client/UI/Components/FullScreenToggler.ts +14 -23
  36. package/src/Client/UI/Components/KeyboardAccelerator.ts +9 -8
  37. package/src/Client/UI/Components/LoadingIndicator.ts +1 -0
  38. package/src/Client/UI/Components/MenuActivator.ts +7 -7
  39. package/src/Client/UI/Components/OfflineIndicator.ts +6 -4
  40. package/src/Client/UI/Components/ThemeDropdown.ts +6 -5
  41. package/src/Client/UI/Components/Toast.ts +10 -6
  42. package/lib/UI/Signal.d.ts +0 -16
  43. package/lib/UI/Signal.d.ts.map +0 -1
  44. package/src/Client/UI/Signal.ts +0 -18
package/lib/Htmx.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import htmx, { type HtmxResponseInfo } from "htmx.org";
2
+ export declare const Htmx: typeof htmx.default;
3
+ /**
4
+ * Provides details about an `htmx` event.
5
+ */
6
+ export type HtmxEventDetail = HtmxResponseInfo & {
7
+ /**
8
+ * The element involved in the operation that just occurred.
9
+ */
10
+ elt: Element;
11
+ };
12
+ //# sourceMappingURL=Htmx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Htmx.d.ts","sourceRoot":"","sources":["../src/Client/Htmx.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAC,KAAK,gBAAgB,EAAC,MAAM,UAAU,CAAC;AACrD,eAAO,MAAM,IAAI,EAAsB,OAAO,IAAI,CAAC,OAAO,CAAC;AAE3D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAEhD;;OAEG;IACH,GAAG,EAAE,OAAO,CAAC;CACb,CAAC"}
package/lib/Htmx.js ADDED
@@ -0,0 +1,2 @@
1
+ import htmx, {} from "htmx.org";
2
+ export const Htmx = htmx;
@@ -0,0 +1,16 @@
1
+ import { Computed, Signal as State } from "@preact/signals-core";
2
+ export { effect, Computed, type EffectOptions, Signal as State } from "@preact/signals-core";
3
+ /**
4
+ * Creates reactive primitives.
5
+ */
6
+ export declare const Signal: Readonly<{
7
+ /**
8
+ * Creates a new computed signal.
9
+ */
10
+ Computed: typeof Computed;
11
+ /**
12
+ * Creates a new plain signal.
13
+ */
14
+ State: typeof State;
15
+ }>;
16
+ //# sourceMappingURL=Signal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Signal.d.ts","sourceRoot":"","sources":["../src/Client/Signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,EAAC,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,IAAI,KAAK,EAAC,MAAM,sBAAsB,CAAC;AAE3F;;GAEG;AACH,eAAO,MAAM,MAAM;IAElB;;OAEG;;IAGH;;OAEG;;EAEF,CAAC"}
@@ -1,15 +1,15 @@
1
1
  import { Computed, Signal as State } from "@preact/signals-core";
2
- export { effect } from "@preact/signals-core";
2
+ export { effect, Computed, Signal as State } from "@preact/signals-core";
3
3
  /**
4
4
  * Creates reactive primitives.
5
5
  */
6
- export class Signal {
6
+ export const Signal = Object.freeze({
7
7
  /**
8
8
  * Creates a new computed signal.
9
9
  */
10
- static Computed = Computed;
10
+ Computed,
11
11
  /**
12
12
  * Creates a new plain signal.
13
13
  */
14
- static State = State;
15
- }
14
+ State
15
+ });
@@ -1,4 +1,4 @@
1
- import { type EffectOptions } from "./Signal.js";
1
+ import { type EffectOptions } from "../Signal.js";
2
2
  /**
3
3
  * The base class for signal-based custom elements.
4
4
  */
@@ -10,9 +10,9 @@ export declare abstract class Component extends HTMLElement {
10
10
  disconnectedCallback(): void;
11
11
  /**
12
12
  * Registers a new effect.
13
- * @param callback The effect computation.
13
+ * @param handler The effect handler.
14
14
  * @param options The effect options.
15
15
  */
16
- useEffect(callback: () => void, options?: EffectOptions): void;
16
+ useEffect(handler: (() => void) | (() => () => void), options?: EffectOptions): void;
17
17
  }
18
18
  //# sourceMappingURL=Component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Component.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,aAAa,CAAC;AAEvD;;GAEG;AACH,8BAAsB,SAAU,SAAQ,WAAW;;IAOlD;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI;CAG9D"}
1
+ {"version":3,"file":"Component.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,cAAc,CAAC;AAExD;;GAEG;AACH,8BAAsB,SAAU,SAAQ,WAAW;;IAOlD;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI;CAGpF"}
@@ -1,4 +1,4 @@
1
- import { effect } from "./Signal.js";
1
+ import { effect } from "../Signal.js";
2
2
  /**
3
3
  * The base class for signal-based custom elements.
4
4
  */
@@ -17,10 +17,10 @@ export class Component extends HTMLElement {
17
17
  }
18
18
  /**
19
19
  * Registers a new effect.
20
- * @param callback The effect computation.
20
+ * @param handler The effect handler.
21
21
  * @param options The effect options.
22
22
  */
23
- useEffect(callback, options) {
24
- this.#effects.push(effect(callback, options));
23
+ useEffect(handler, options) {
24
+ this.#effects.push(effect(handler, options));
25
25
  }
26
26
  }
@@ -2,10 +2,6 @@
2
2
  * A component that moves back in the session history when clicked.
3
3
  */
4
4
  export declare class BackButton extends HTMLElement {
5
- /**
6
- * Creates a new back button.
7
- */
8
- constructor();
9
5
  /**
10
6
  * The number of pages to go back.
11
7
  */
@@ -15,7 +11,7 @@ export declare class BackButton extends HTMLElement {
15
11
  * Moves back in the session history.
16
12
  * @param event The dispatched event.
17
13
  */
18
- readonly goBack: (event?: Event) => void;
14
+ goBack(event?: Event): void;
19
15
  }
20
16
  /**
21
17
  * Declaration merging.
@@ -1 +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;IAED;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAGtC;CACF;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,aAAa,EAAE,UAAU,CAAC;KAC1B;CACD"}
1
+ {"version":3,"file":"BackButton.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/BackButton.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAW,SAAQ,WAAW;IAS1C;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;CAI3B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,aAAa,EAAE,UAAU,CAAC;KAC1B;CACD"}
@@ -2,13 +2,6 @@
2
2
  * A component that moves back in the session history when clicked.
3
3
  */
4
4
  export class BackButton extends HTMLElement {
5
- /**
6
- * Creates a new back button.
7
- */
8
- constructor() {
9
- super();
10
- this.addEventListener("click", this.goBack, { capture: true });
11
- }
12
5
  /**
13
6
  * Registers the component.
14
7
  */
@@ -29,8 +22,8 @@ export class BackButton extends HTMLElement {
29
22
  * Moves back in the session history.
30
23
  * @param event The dispatched event.
31
24
  */
32
- goBack = event => {
33
- event?.stopPropagation();
25
+ goBack(event) {
26
+ event?.preventDefault();
34
27
  history.go(-this.steps);
35
- };
28
+ }
36
29
  }
@@ -128,12 +128,12 @@ export class DialogBox extends HTMLElement {
128
128
  case "centered":
129
129
  this.#updateCentered(newValue != null);
130
130
  break;
131
- case "modal":
132
- this.#updateModal(newValue != null);
133
- break;
134
131
  case "fade":
135
132
  this.#updateFade(newValue != null);
136
133
  break;
134
+ case "modal":
135
+ this.#updateModal(newValue != null);
136
+ break;
137
137
  case "scrollable":
138
138
  this.#updateScrollable(newValue != null);
139
139
  break;
@@ -3,10 +3,6 @@
3
3
  */
4
4
  export declare class FullScreenToggler extends HTMLElement {
5
5
  #private;
6
- /**
7
- * Creates a new full-screen toggler.
8
- */
9
- constructor();
10
6
  /**
11
7
  * The CSS selector specifying the target element.
12
8
  */
@@ -30,7 +26,7 @@ export declare class FullScreenToggler extends HTMLElement {
30
26
  * @param event The dispatched event.
31
27
  * @returns Completes when the full-screen mode has been toggled.
32
28
  */
33
- readonly toggleFullScreen: (event?: Event) => Promise<void>;
29
+ toggleFullScreen(event?: Event): Promise<void>;
34
30
  }
35
31
  /**
36
32
  * Declaration merging.
@@ -1 +1 @@
1
- {"version":3,"file":"FullScreenToggler.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/FullScreenToggler.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;;IAiBjD;;OAEG;;IAaH;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAGnB;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAEvB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAI5B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAIzD;CAoCF;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,oBAAoB,EAAE,iBAAiB,CAAC;KACxC;CACD"}
1
+ {"version":3,"file":"FullScreenToggler.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/FullScreenToggler.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;;IAwBjD;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAGnB;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAEvB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAOzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAI5B;;;;OAIG;IACG,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;CAsCpD;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,oBAAoB,EAAE,iBAAiB,CAAC;KACxC;CACD"}
@@ -5,7 +5,7 @@ export class FullScreenToggler extends HTMLElement {
5
5
  /**
6
6
  * The abort controller used to remove the event listeners.
7
7
  */
8
- #abortController = new AbortController;
8
+ #abortController = null;
9
9
  /**
10
10
  * The target element.
11
11
  */
@@ -14,13 +14,6 @@ export class FullScreenToggler extends HTMLElement {
14
14
  * The handle to the underlying platform wake lock.
15
15
  */
16
16
  #sentinel = null;
17
- /**
18
- * Creates a new full-screen toggler.
19
- */
20
- constructor() {
21
- super();
22
- this.addEventListener("click", this.toggleFullScreen, { capture: true }); // eslint-disable-line @typescript-eslint/no-misused-promises
23
- }
24
17
  /**
25
18
  * Registers the component.
26
19
  */
@@ -50,63 +43,61 @@ export class FullScreenToggler extends HTMLElement {
50
43
  * Method invoked when this component is connected.
51
44
  */
52
45
  connectedCallback() {
53
- document.addEventListener("visibilitychange", this.#onVisibilityChanged, { signal: this.#abortController.signal });
46
+ this.#abortController = new AbortController;
47
+ document.addEventListener("visibilitychange", () => this.#onVisibilityChanged(), { signal: this.#abortController.signal });
54
48
  this.#element = document.querySelector(this.target) ?? document.body;
55
- this.#element.addEventListener("fullscreenchange", this.#onFullScreenChanged, { signal: this.#abortController.signal });
49
+ this.#element.addEventListener("fullscreenchange", () => this.#onFullScreenChanged(), { signal: this.#abortController.signal });
56
50
  }
57
51
  /**
58
52
  * Method invoked when this component is disconnected.
59
53
  */
60
54
  disconnectedCallback() {
61
- this.#abortController.abort();
55
+ this.#abortController?.abort();
62
56
  }
63
57
  /**
64
58
  * Toggles the full-screen mode of the associated element.
65
59
  * @param event The dispatched event.
66
60
  * @returns Completes when the full-screen mode has been toggled.
67
61
  */
68
- toggleFullScreen = async (event) => {
69
- event?.stopPropagation();
62
+ async toggleFullScreen(event) {
63
+ event?.preventDefault();
70
64
  if (document.fullscreenElement)
71
65
  await document.exitFullscreen();
72
66
  else
73
67
  await this.#element.requestFullscreen();
74
- };
68
+ }
75
69
  /**
76
70
  * Acquires a new wake lock.
77
71
  * @returns Completes when the wake lock has been acquired.
78
72
  */
79
73
  async #acquireWakeLock() {
80
- if (this.#sentinel && !this.#sentinel.released)
81
- return;
82
- if (this.wakeLock)
74
+ if (this.wakeLock && (!this.#sentinel || this.#sentinel.released))
83
75
  this.#sentinel = await navigator.wakeLock.request();
84
76
  }
85
77
  /**
86
78
  * Acquires or releases the wake lock when the document enters or exits the full-screen mode.
87
79
  * @param event The dispatched event.
88
80
  */
89
- #onFullScreenChanged = () => {
81
+ #onFullScreenChanged() {
90
82
  if (document.fullscreenElement)
91
83
  void this.#acquireWakeLock();
92
84
  else
93
85
  void this.#releaseWakeLock();
94
- };
86
+ }
95
87
  /**
96
88
  * Eventually acquires a new wake lock when the document visibility has changed.
97
89
  * @param event The dispatched event.
98
90
  */
99
- #onVisibilityChanged = () => {
91
+ #onVisibilityChanged() {
100
92
  if (document.fullscreenElement && !document.hidden)
101
93
  void this.#acquireWakeLock();
102
- };
94
+ }
103
95
  /**
104
96
  * Releases the acquired wake lock.
105
97
  * @returns Completes when the wake lock has been released.
106
98
  */
107
99
  async #releaseWakeLock() {
108
- if (!this.#sentinel || this.#sentinel.released)
109
- return;
110
- await this.#sentinel.release();
100
+ if (this.#sentinel && !this.#sentinel.released)
101
+ await this.#sentinel.release();
111
102
  }
112
103
  }
@@ -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;;IAmBnD;;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"}
1
+ {"version":3,"file":"KeyboardAccelerator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/KeyboardAccelerator.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;;IAmBnD;;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;IAKzB;;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"}
@@ -3,14 +3,14 @@ import { KeyboardModifiers } from "../KeyboardModifiers.js";
3
3
  * Represents a shortcut key associated with an element.
4
4
  */
5
5
  export class KeyboardAccelerator extends HTMLElement {
6
- /**
7
- * The abort controller used to remove the event listeners.
8
- */
9
- #abortController = new AbortController;
10
6
  /**
11
7
  * The mapping between the modifier names and their values.
12
8
  */
13
9
  static #modifiers = new Map(Object.entries(KeyboardModifiers).filter(([key]) => key != "None"));
10
+ /**
11
+ * The abort controller used to remove the event listeners.
12
+ */
13
+ #abortController = null;
14
14
  /**
15
15
  * Registers the component.
16
16
  */
@@ -44,19 +44,20 @@ export class KeyboardAccelerator extends HTMLElement {
44
44
  * Method invoked when this component is connected.
45
45
  */
46
46
  connectedCallback() {
47
- addEventListener("keyup", this.#activateChildContent, { capture: true, signal: this.#abortController.signal });
47
+ this.#abortController = new AbortController;
48
+ addEventListener("keyup", event => this.#activateChildContent(event), { signal: this.#abortController.signal });
48
49
  }
49
50
  /**
50
51
  * Method invoked when this component is disconnected.
51
52
  */
52
53
  disconnectedCallback() {
53
- this.#abortController.abort();
54
+ this.#abortController?.abort();
54
55
  }
55
56
  /**
56
57
  * Activates the child content when the specified keyboard event designates the same key and modifiers as this keyboard accelerator.
57
58
  * @param event The dispatched event.
58
59
  */
59
- #activateChildContent = event => {
60
+ #activateChildContent(event) {
60
61
  if (event.key != this.key)
61
62
  return;
62
63
  const { activeElement } = document;
@@ -71,7 +72,7 @@ export class KeyboardAccelerator extends HTMLElement {
71
72
  return;
72
73
  if (!(modifiers & KeyboardModifiers.Meta) && event.metaKey)
73
74
  return;
74
- event.stopPropagation();
75
+ event.preventDefault();
75
76
  this.firstElementChild?.click();
76
- };
77
+ }
77
78
  }
@@ -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;;IAEhD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAY;IAc9C;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAO/F;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;;OAGG;IACH,IAAI,CAAC,OAAO,GAAE;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAM,GAAG,IAAI;IAS3C;;OAEG;IACH,IAAI,IAAI,IAAI;CAaZ;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;;IAEhD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAY;IAc9C;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAO/F;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAKzB;;;OAGG;IACH,IAAI,CAAC,OAAO,GAAE;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAM,GAAG,IAAI;IAS3C;;OAEG;IACH,IAAI,IAAI,IAAI;CAaZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,gBAAgB,CAAC;KACtC;CACD"}
@@ -59,6 +59,7 @@ export class LoadingIndicator extends HTMLElement {
59
59
  * Method invoked when this component is connected.
60
60
  */
61
61
  connectedCallback() {
62
+ this.#requestCount = 0;
62
63
  if (this.open)
63
64
  this.show();
64
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MenuActivator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/MenuActivator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAc7C;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAe5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,aAAa,CAAC;KAChC;CACD"}
1
+ {"version":3,"file":"MenuActivator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/MenuActivator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAc7C;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAOzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAc5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,aAAa,CAAC;KAChC;CACD"}
@@ -5,7 +5,7 @@ export class MenuActivator extends HTMLElement {
5
5
  /**
6
6
  * The abort controller used to remove the event listeners.
7
7
  */
8
- #abortController = new AbortController;
8
+ #abortController = null;
9
9
  /**
10
10
  * Registers the component.
11
11
  */
@@ -16,21 +16,21 @@ export class MenuActivator extends HTMLElement {
16
16
  * Method invoked when this component is connected.
17
17
  */
18
18
  connectedCallback() {
19
+ this.#abortController = new AbortController;
19
20
  this.#update();
20
- addEventListener("popstate", this.#update, { signal: this.#abortController.signal });
21
- document.body.addEventListener("htmx:afterRequest", this.#update, { signal: this.#abortController.signal });
21
+ addEventListener("popstate", () => this.#update(), { signal: this.#abortController.signal });
22
+ document.body.addEventListener("htmx:pushedIntoHistory", () => this.#update(), { signal: this.#abortController.signal });
22
23
  }
23
24
  /**
24
25
  * Method invoked when this component is disconnected.
25
26
  */
26
27
  disconnectedCallback() {
27
- this.#abortController.abort();
28
+ this.#abortController?.abort();
28
29
  }
29
30
  /**
30
31
  * Updates this component.
31
- * @param event The dispatched event.
32
32
  */
33
- #update = () => {
33
+ #update() {
34
34
  for (const element of this.querySelectorAll(".active"))
35
35
  element.classList.remove("active");
36
36
  for (const element of this.querySelectorAll("a"))
@@ -38,5 +38,5 @@ export class MenuActivator extends HTMLElement {
38
38
  element.classList.add("active");
39
39
  element.closest(".dropdown")?.querySelector(".dropdown-toggle")?.classList.add("active");
40
40
  }
41
- };
41
+ }
42
42
  }
@@ -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;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAY;IAc9C;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAO/F;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAI5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAKZ;;OAEG;IACH,IAAI,IAAI,IAAI;CAoBZ;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;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAY;IAc9C;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAO/F;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAQzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAI5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAKZ;;OAEG;IACH,IAAI,IAAI,IAAI;CAoBZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,gBAAgB,CAAC;KACtC;CACD"}
@@ -9,7 +9,7 @@ export class OfflineIndicator extends HTMLElement {
9
9
  /**
10
10
  * The abort controller used to remove the event listeners.
11
11
  */
12
- #abortController = new AbortController;
12
+ #abortController = null;
13
13
  /**
14
14
  * Registers the component.
15
15
  */
@@ -59,8 +59,9 @@ export class OfflineIndicator extends HTMLElement {
59
59
  * Method invoked when this component is connected.
60
60
  */
61
61
  connectedCallback() {
62
+ this.#abortController = new AbortController;
62
63
  for (const event of ["online", "offline"])
63
- addEventListener(event, this.#updateVisibility, { signal: this.#abortController.signal });
64
+ addEventListener(event, () => this.#updateVisibility(), { signal: this.#abortController.signal });
64
65
  if (this.open)
65
66
  this.show();
66
67
  else
@@ -70,7 +71,7 @@ export class OfflineIndicator extends HTMLElement {
70
71
  * Method invoked when this component is disconnected.
71
72
  */
72
73
  disconnectedCallback() {
73
- this.#abortController.abort();
74
+ this.#abortController?.abort();
74
75
  }
75
76
  /**
76
77
  * Hides this offline indicator.
@@ -96,10 +97,10 @@ export class OfflineIndicator extends HTMLElement {
96
97
  /**
97
98
  * Updates the visibility of this component.
98
99
  */
99
- #updateVisibility = () => {
100
+ #updateVisibility() {
100
101
  if (navigator.onLine)
101
102
  this.hide();
102
103
  else
103
104
  this.show();
104
- };
105
+ }
105
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ThemeDropdown.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/ThemeDropdown.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAC,QAAQ,EAAO,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAsC;IAiBxE;;OAEG;;IAaH;;OAEG;IACH,IAAI,SAAS,IAAI,SAAS,CAGzB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,SAAS,EAE7B;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,QAAQ,CAGvB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAE3B;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,EAExB;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IACD,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;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;IAS/F;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAYxC;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,IAAI,IAAI,IAAI;CAwDZ;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":"AACA,OAAO,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAC,QAAQ,EAAO,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAsC;IAiBxE;;OAEG;;IAaH;;OAEG;IACH,IAAI,SAAS,IAAI,SAAS,CAGzB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,SAAS,EAE7B;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,QAAQ,CAGvB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAE3B;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,EAExB;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IACD,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;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;IAS/F;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAaxC;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,IAAI,IAAI,IAAI;CAwDZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,aAAa,CAAC;KAChC;CACD"}
@@ -12,7 +12,7 @@ export class ThemeDropdown extends HTMLElement {
12
12
  /**
13
13
  * The abort controller used to remove the event listeners.
14
14
  */
15
- #abortController = new AbortController;
15
+ #abortController = null;
16
16
  /**
17
17
  * The dropdown menu.
18
18
  */
@@ -125,8 +125,9 @@ export class ThemeDropdown extends HTMLElement {
125
125
  * @returns Completes when this component has been connected.
126
126
  */
127
127
  async connectedCallback() {
128
+ this.#abortController = new AbortController;
128
129
  this.#dropdown = new Dropdown(this.querySelector(".dropdown-toggle"));
129
- this.#mediaQuery.addEventListener("change", this.#applyToDocument, { signal: this.#abortController.signal });
130
+ this.#mediaQuery.addEventListener("change", () => this.#applyToDocument(), { signal: this.#abortController.signal });
130
131
  const cookie = this.cookie ? await cookieStore.get(this.storageKey) : null;
131
132
  if (cookie)
132
133
  this.appTheme = cookie.value;
@@ -140,7 +141,7 @@ export class ThemeDropdown extends HTMLElement {
140
141
  * Method invoked when this component is disconnected.
141
142
  */
142
143
  disconnectedCallback() {
143
- this.#abortController.abort();
144
+ this.#abortController?.abort();
144
145
  this.#dropdown.dispose();
145
146
  }
146
147
  /**
@@ -166,11 +167,11 @@ export class ThemeDropdown extends HTMLElement {
166
167
  /**
167
168
  * Applies the application theme to the document.
168
169
  */
169
- #applyToDocument = () => {
170
+ #applyToDocument() {
170
171
  const { appTheme } = this;
171
172
  const bsTheme = appTheme == AppTheme.System ? (this.#mediaQuery.matches ? AppTheme.Dark : AppTheme.Light) : appTheme;
172
173
  document.documentElement.dataset.bsTheme = bsTheme.toLowerCase();
173
- };
174
+ }
174
175
  /**
175
176
  * Changes the current application theme.
176
177
  * @param event The dispatched event.
@@ -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,eAAe,CAAC;AAEtD;;GAEG;AACH,qBAAa,KAAM,SAAQ,WAAW;;IAErC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAA0E;IAuC5G;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,IAAI,IAAI,CAAC,KAAK,EAAE,gBAAgB,EAE/B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,EAExB;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,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,GAAC,IAAI,CAGtB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,GAAC,IAAI,EAG1B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAa/F;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,iBAAiB,IAAI,IAAI;IASzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAM5B;;OAEG;IACH,IAAI,IAAI,IAAI;CAsGZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,cAAc,EAAE,KAAK,CAAC;KACtB;CACD"}
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,WAA0E;IAuC5G;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,IAAI,IAAI,CAAC,KAAK,EAAE,gBAAgB,EAE/B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,EAExB;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,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,GAAC,IAAI,CAGtB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,GAAC,IAAI,EAG1B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAa/F;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAWzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAM5B;;OAEG;IACH,IAAI,IAAI,IAAI;CAwGZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,cAAc,EAAE,KAAK,CAAC;KACtB;CACD"}
@@ -15,7 +15,7 @@ export class Toast extends HTMLElement {
15
15
  /**
16
16
  * The abort controller used to remove the event listeners.
17
17
  */
18
- #abortController = new AbortController;
18
+ #abortController = null;
19
19
  /**
20
20
  * The formatter used to format the relative time.
21
21
  */
@@ -172,9 +172,10 @@ export class Toast extends HTMLElement {
172
172
  * Method invoked when this component is connected.
173
173
  */
174
174
  connectedCallback() {
175
+ this.#abortController = new AbortController;
175
176
  const root = this.firstElementChild;
176
- root.addEventListener("hide.bs.toast", this.#stopTimer, { signal: this.#abortController.signal });
177
- root.addEventListener("show.bs.toast", this.#startTimer, { signal: this.#abortController.signal });
177
+ root.addEventListener("hide.bs.toast", () => this.#stopTimer(), { signal: this.#abortController.signal });
178
+ root.addEventListener("show.bs.toast", () => this.#startTimer(), { signal: this.#abortController.signal });
178
179
  this.#toast = new BootstrapToast(root);
179
180
  if (this.open)
180
181
  this.show();
@@ -184,7 +185,7 @@ export class Toast extends HTMLElement {
184
185
  */
185
186
  disconnectedCallback() {
186
187
  this.#stopTimer();
187
- this.#abortController.abort();
188
+ this.#abortController?.abort();
188
189
  this.#toast.dispose();
189
190
  }
190
191
  /**
@@ -213,11 +214,15 @@ export class Toast extends HTMLElement {
213
214
  /**
214
215
  * Starts the timer.
215
216
  */
216
- #startTimer = () => this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000);
217
+ #startTimer() {
218
+ this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000);
219
+ }
217
220
  /**
218
221
  * Stops the timer.
219
222
  */
220
- #stopTimer = () => clearInterval(this.#timer);
223
+ #stopTimer() {
224
+ clearInterval(this.#timer);
225
+ }
221
226
  /**
222
227
  * Updates the value indicating whether to automatically hide this toast.
223
228
  * @param value The new value.
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.36.2",
10
+ "version": "0.37.0",
11
11
  "dependencies": {
12
12
  "@preact/signals-core": "^1.13.0"
13
13
  },
@@ -16,12 +16,13 @@
16
16
  "@types/bootstrap": "^5.2.10",
17
17
  "@types/chai": "^5.2.3",
18
18
  "@types/mocha": "^10.0.10",
19
- "@types/node": "^25.2.3",
19
+ "@types/node": "^25.3.0",
20
20
  "@types/serve-handler": "^6.1.4",
21
21
  "bootstrap": "^5.3.8",
22
22
  "chai": "^6.2.2",
23
23
  "esbuild": "^0.27.3",
24
24
  "globals": "^17.3.0",
25
+ "htmx.org": "^2.0.8",
25
26
  "mocha": "^11.7.5",
26
27
  "playwright": "^1.58.2",
27
28
  "playwright-chromium": "^1.58.2",
@@ -50,7 +51,8 @@
50
51
  "library"
51
52
  ],
52
53
  "peerDependencies": {
53
- "bootstrap": ">=5.3.0"
54
+ "bootstrap": ">=5.3.0",
55
+ "htmx.org": ">=2.0.0"
54
56
  },
55
57
  "publishConfig": {
56
58
  "access": "public"
@@ -0,0 +1,13 @@
1
+ import htmx, {type HtmxResponseInfo} from "htmx.org";
2
+ export const Htmx = htmx as unknown as typeof htmx.default;
3
+
4
+ /**
5
+ * Provides details about an `htmx` event.
6
+ */
7
+ export type HtmxEventDetail = HtmxResponseInfo & {
8
+
9
+ /**
10
+ * The element involved in the operation that just occurred.
11
+ */
12
+ elt: Element;
13
+ };
@@ -0,0 +1,18 @@
1
+ import {Computed, Signal as State} from "@preact/signals-core";
2
+ export {effect, Computed, type EffectOptions, Signal as State} from "@preact/signals-core";
3
+
4
+ /**
5
+ * Creates reactive primitives.
6
+ */
7
+ export const Signal = Object.freeze({
8
+
9
+ /**
10
+ * Creates a new computed signal.
11
+ */
12
+ Computed,
13
+
14
+ /**
15
+ * Creates a new plain signal.
16
+ */
17
+ State
18
+ });
@@ -1,4 +1,4 @@
1
- import {effect, type EffectOptions} from "./Signal.js";
1
+ import {effect, type EffectOptions} from "../Signal.js";
2
2
 
3
3
  /**
4
4
  * The base class for signal-based custom elements.
@@ -20,10 +20,10 @@ export abstract class Component extends HTMLElement {
20
20
 
21
21
  /**
22
22
  * Registers a new effect.
23
- * @param callback The effect computation.
23
+ * @param handler The effect handler.
24
24
  * @param options The effect options.
25
25
  */
26
- useEffect(callback: () => void, options?: EffectOptions): void {
27
- this.#effects.push(effect(callback, options));
26
+ useEffect(handler: (() => void) | (() => () => void), options?: EffectOptions): void {
27
+ this.#effects.push(effect(handler, options));
28
28
  }
29
29
  }
@@ -3,14 +3,6 @@
3
3
  */
4
4
  export class BackButton extends HTMLElement {
5
5
 
6
- /**
7
- * Creates a new back button.
8
- */
9
- constructor() {
10
- super();
11
- this.addEventListener("click", this.goBack, {capture: true});
12
- }
13
-
14
6
  /**
15
7
  * Registers the component.
16
8
  */
@@ -33,10 +25,10 @@ export class BackButton extends HTMLElement {
33
25
  * Moves back in the session history.
34
26
  * @param event The dispatched event.
35
27
  */
36
- readonly goBack: (event?: Event) => void = event => {
37
- event?.stopPropagation();
28
+ goBack(event?: Event): void {
29
+ event?.preventDefault();
38
30
  history.go(-this.steps);
39
- };
31
+ }
40
32
  }
41
33
 
42
34
  /**
@@ -186,8 +186,8 @@ export class DialogBox extends HTMLElement {
186
186
  if (newValue != oldValue) switch (attribute) {
187
187
  case "caption": this.#updateCaption(newValue ?? ""); break;
188
188
  case "centered": this.#updateCentered(newValue != null); break;
189
- case "modal": this.#updateModal(newValue != null); break;
190
189
  case "fade": this.#updateFade(newValue != null); break;
190
+ case "modal": this.#updateModal(newValue != null); break;
191
191
  case "scrollable": this.#updateScrollable(newValue != null); break;
192
192
  // No default
193
193
  }
@@ -6,7 +6,7 @@ export class FullScreenToggler extends HTMLElement {
6
6
  /**
7
7
  * The abort controller used to remove the event listeners.
8
8
  */
9
- readonly #abortController = new AbortController;
9
+ #abortController: AbortController|null = null;
10
10
 
11
11
  /**
12
12
  * The target element.
@@ -18,14 +18,6 @@ export class FullScreenToggler extends HTMLElement {
18
18
  */
19
19
  #sentinel: WakeLockSentinel|null = null;
20
20
 
21
- /**
22
- * Creates a new full-screen toggler.
23
- */
24
- constructor() {
25
- super();
26
- this.addEventListener("click", this.toggleFullScreen, {capture: true}); // eslint-disable-line @typescript-eslint/no-misused-promises
27
- }
28
-
29
21
  /**
30
22
  * Registers the component.
31
23
  */
@@ -58,16 +50,17 @@ export class FullScreenToggler extends HTMLElement {
58
50
  * Method invoked when this component is connected.
59
51
  */
60
52
  connectedCallback(): void {
61
- document.addEventListener("visibilitychange", this.#onVisibilityChanged, {signal: this.#abortController.signal});
53
+ this.#abortController = new AbortController;
54
+ document.addEventListener("visibilitychange", () => this.#onVisibilityChanged(), {signal: this.#abortController.signal});
62
55
  this.#element = document.querySelector(this.target) ?? document.body;
63
- this.#element.addEventListener("fullscreenchange", this.#onFullScreenChanged, {signal: this.#abortController.signal});
56
+ this.#element.addEventListener("fullscreenchange", () => this.#onFullScreenChanged(), {signal: this.#abortController.signal});
64
57
  }
65
58
 
66
59
  /**
67
60
  * Method invoked when this component is disconnected.
68
61
  */
69
62
  disconnectedCallback(): void {
70
- this.#abortController.abort();
63
+ this.#abortController?.abort();
71
64
  }
72
65
 
73
66
  /**
@@ -75,45 +68,43 @@ export class FullScreenToggler extends HTMLElement {
75
68
  * @param event The dispatched event.
76
69
  * @returns Completes when the full-screen mode has been toggled.
77
70
  */
78
- readonly toggleFullScreen: (event?: Event) => Promise<void> = async event => {
79
- event?.stopPropagation();
71
+ async toggleFullScreen(event?: Event): Promise<void> {
72
+ event?.preventDefault();
80
73
  if (document.fullscreenElement) await document.exitFullscreen();
81
74
  else await this.#element.requestFullscreen();
82
- };
75
+ }
83
76
 
84
77
  /**
85
78
  * Acquires a new wake lock.
86
79
  * @returns Completes when the wake lock has been acquired.
87
80
  */
88
81
  async #acquireWakeLock(): Promise<void> {
89
- if (this.#sentinel && !this.#sentinel.released) return;
90
- if (this.wakeLock) this.#sentinel = await navigator.wakeLock.request();
82
+ if (this.wakeLock && (!this.#sentinel || this.#sentinel.released)) this.#sentinel = await navigator.wakeLock.request();
91
83
  }
92
84
 
93
85
  /**
94
86
  * Acquires or releases the wake lock when the document enters or exits the full-screen mode.
95
87
  * @param event The dispatched event.
96
88
  */
97
- readonly #onFullScreenChanged: (event: Event) => void = () => {
89
+ #onFullScreenChanged(): void {
98
90
  if (document.fullscreenElement) void this.#acquireWakeLock();
99
91
  else void this.#releaseWakeLock();
100
- };
92
+ }
101
93
 
102
94
  /**
103
95
  * Eventually acquires a new wake lock when the document visibility has changed.
104
96
  * @param event The dispatched event.
105
97
  */
106
- readonly #onVisibilityChanged: (event: Event) => void = () => {
98
+ #onVisibilityChanged(): void {
107
99
  if (document.fullscreenElement && !document.hidden) void this.#acquireWakeLock();
108
- };
100
+ }
109
101
 
110
102
  /**
111
103
  * Releases the acquired wake lock.
112
104
  * @returns Completes when the wake lock has been released.
113
105
  */
114
106
  async #releaseWakeLock(): Promise<void> {
115
- if (!this.#sentinel || this.#sentinel.released) return;
116
- await this.#sentinel.release();
107
+ if (this.#sentinel && !this.#sentinel.released) await this.#sentinel.release();
117
108
  }
118
109
  }
119
110
 
@@ -6,14 +6,14 @@ import {KeyboardModifiers} from "../KeyboardModifiers.js";
6
6
  export class KeyboardAccelerator extends HTMLElement {
7
7
 
8
8
  /**
9
- * The abort controller used to remove the event listeners.
9
+ * The mapping between the modifier names and their values.
10
10
  */
11
- readonly #abortController = new AbortController;
11
+ static readonly #modifiers = new Map(Object.entries(KeyboardModifiers).filter(([key]) => key != "None"));
12
12
 
13
13
  /**
14
- * The mapping between the modifier names and their values.
14
+ * The abort controller used to remove the event listeners.
15
15
  */
16
- static readonly #modifiers = new Map(Object.entries(KeyboardModifiers).filter(([key]) => key != "None"));
16
+ #abortController: AbortController|null = null;
17
17
 
18
18
  /**
19
19
  * Registers the component.
@@ -51,21 +51,22 @@ export class KeyboardAccelerator extends HTMLElement {
51
51
  * Method invoked when this component is connected.
52
52
  */
53
53
  connectedCallback(): void {
54
- addEventListener("keyup", this.#activateChildContent, {capture: true, signal: this.#abortController.signal});
54
+ this.#abortController = new AbortController;
55
+ addEventListener("keyup", event => this.#activateChildContent(event), {signal: this.#abortController.signal});
55
56
  }
56
57
 
57
58
  /**
58
59
  * Method invoked when this component is disconnected.
59
60
  */
60
61
  disconnectedCallback(): void {
61
- this.#abortController.abort();
62
+ this.#abortController?.abort();
62
63
  }
63
64
 
64
65
  /**
65
66
  * Activates the child content when the specified keyboard event designates the same key and modifiers as this keyboard accelerator.
66
67
  * @param event The dispatched event.
67
68
  */
68
- readonly #activateChildContent: (event: KeyboardEvent) => void = event => {
69
+ #activateChildContent(event: KeyboardEvent): void {
69
70
  if (event.key != this.key) return;
70
71
 
71
72
  const {activeElement} = document;
@@ -77,7 +78,7 @@ export class KeyboardAccelerator extends HTMLElement {
77
78
  if (!(modifiers & KeyboardModifiers.Alt) && event.altKey) return;
78
79
  if (!(modifiers & KeyboardModifiers.Meta) && event.metaKey) return;
79
80
 
80
- event.stopPropagation();
81
+ event.preventDefault();
81
82
  (this.firstElementChild as HTMLElement|null)?.click();
82
83
  }
83
84
  }
@@ -64,6 +64,7 @@ export class LoadingIndicator extends HTMLElement {
64
64
  * Method invoked when this component is connected.
65
65
  */
66
66
  connectedCallback(): void {
67
+ this.#requestCount = 0;
67
68
  if (this.open) this.show();
68
69
  }
69
70
 
@@ -6,7 +6,7 @@ export class MenuActivator extends HTMLElement {
6
6
  /**
7
7
  * The abort controller used to remove the event listeners.
8
8
  */
9
- readonly #abortController = new AbortController;
9
+ #abortController: AbortController|null = null;
10
10
 
11
11
  /**
12
12
  * Registers the component.
@@ -19,29 +19,29 @@ export class MenuActivator extends HTMLElement {
19
19
  * Method invoked when this component is connected.
20
20
  */
21
21
  connectedCallback(): void {
22
+ this.#abortController = new AbortController;
22
23
  this.#update();
23
- addEventListener("popstate", this.#update, {signal: this.#abortController.signal});
24
- document.body.addEventListener("htmx:afterRequest", this.#update, {signal: this.#abortController.signal});
24
+ addEventListener("popstate", () => this.#update(), {signal: this.#abortController.signal});
25
+ document.body.addEventListener("htmx:pushedIntoHistory", () => this.#update(), {signal: this.#abortController.signal});
25
26
  }
26
27
 
27
28
  /**
28
29
  * Method invoked when this component is disconnected.
29
30
  */
30
31
  disconnectedCallback(): void {
31
- this.#abortController.abort();
32
+ this.#abortController?.abort();
32
33
  }
33
34
 
34
35
  /**
35
36
  * Updates this component.
36
- * @param event The dispatched event.
37
37
  */
38
- readonly #update: (event?: Event) => void = () => {
38
+ #update(): void {
39
39
  for (const element of this.querySelectorAll(".active")) element.classList.remove("active");
40
40
  for (const element of this.querySelectorAll("a")) if (element.href == location.href) {
41
41
  element.classList.add("active");
42
42
  element.closest(".dropdown")?.querySelector(".dropdown-toggle")?.classList.add("active");
43
43
  }
44
- };
44
+ }
45
45
  }
46
46
 
47
47
  /**
@@ -11,7 +11,7 @@ export class OfflineIndicator extends HTMLElement {
11
11
  /**
12
12
  * The abort controller used to remove the event listeners.
13
13
  */
14
- readonly #abortController = new AbortController;
14
+ #abortController: AbortController|null = null;
15
15
 
16
16
  /**
17
17
  * Registers the component.
@@ -64,7 +64,9 @@ export class OfflineIndicator extends HTMLElement {
64
64
  * Method invoked when this component is connected.
65
65
  */
66
66
  connectedCallback(): void {
67
- for (const event of ["online", "offline"]) addEventListener(event, this.#updateVisibility, {signal: this.#abortController.signal});
67
+ this.#abortController = new AbortController;
68
+ for (const event of ["online", "offline"]) addEventListener(event, () => this.#updateVisibility(), {signal: this.#abortController.signal});
69
+
68
70
  if (this.open) this.show();
69
71
  else this.#updateVisibility();
70
72
  }
@@ -73,7 +75,7 @@ export class OfflineIndicator extends HTMLElement {
73
75
  * Method invoked when this component is disconnected.
74
76
  */
75
77
  disconnectedCallback(): void {
76
- this.#abortController.abort();
78
+ this.#abortController?.abort();
77
79
  }
78
80
 
79
81
  /**
@@ -103,7 +105,7 @@ export class OfflineIndicator extends HTMLElement {
103
105
  /**
104
106
  * Updates the visibility of this component.
105
107
  */
106
- readonly #updateVisibility: () => void = () => {
108
+ #updateVisibility(): void {
107
109
  if (navigator.onLine) this.hide();
108
110
  else this.show();
109
111
  }
@@ -15,7 +15,7 @@ export class ThemeDropdown extends HTMLElement {
15
15
  /**
16
16
  * The abort controller used to remove the event listeners.
17
17
  */
18
- readonly #abortController = new AbortController;
18
+ #abortController: AbortController|null = null;
19
19
 
20
20
  /**
21
21
  * The dropdown menu.
@@ -133,8 +133,9 @@ export class ThemeDropdown extends HTMLElement {
133
133
  * @returns Completes when this component has been connected.
134
134
  */
135
135
  async connectedCallback(): Promise<void> {
136
+ this.#abortController = new AbortController;
136
137
  this.#dropdown = new Dropdown(this.querySelector(".dropdown-toggle")!);
137
- this.#mediaQuery.addEventListener("change", this.#applyToDocument, {signal: this.#abortController.signal});
138
+ this.#mediaQuery.addEventListener("change", () => this.#applyToDocument(), {signal: this.#abortController.signal});
138
139
 
139
140
  const cookie = this.cookie ? await cookieStore.get(this.storageKey) : null;
140
141
  if (cookie) this.appTheme = cookie.value as AppTheme;
@@ -148,7 +149,7 @@ export class ThemeDropdown extends HTMLElement {
148
149
  * Method invoked when this component is disconnected.
149
150
  */
150
151
  disconnectedCallback(): void {
151
- this.#abortController.abort();
152
+ this.#abortController?.abort();
152
153
  this.#dropdown.dispose();
153
154
  }
154
155
 
@@ -177,11 +178,11 @@ export class ThemeDropdown extends HTMLElement {
177
178
  /**
178
179
  * Applies the application theme to the document.
179
180
  */
180
- readonly #applyToDocument: () => void = () => {
181
+ #applyToDocument(): void {
181
182
  const {appTheme} = this;
182
183
  const bsTheme = appTheme == AppTheme.System ? (this.#mediaQuery.matches ? AppTheme.Dark : AppTheme.Light) : appTheme;
183
184
  document.documentElement.dataset.bsTheme = bsTheme.toLowerCase();
184
- };
185
+ }
185
186
 
186
187
  /**
187
188
  * Changes the current application theme.
@@ -19,7 +19,7 @@ export class Toast extends HTMLElement {
19
19
  /**
20
20
  * The abort controller used to remove the event listeners.
21
21
  */
22
- readonly #abortController = new AbortController;
22
+ #abortController: AbortController|null = null;
23
23
 
24
24
  /**
25
25
  * The formatter used to format the relative time.
@@ -177,9 +177,11 @@ export class Toast extends HTMLElement {
177
177
  * Method invoked when this component is connected.
178
178
  */
179
179
  connectedCallback(): void {
180
+ this.#abortController = new AbortController;
181
+
180
182
  const root = this.firstElementChild!;
181
- root.addEventListener("hide.bs.toast", this.#stopTimer, {signal: this.#abortController.signal});
182
- root.addEventListener("show.bs.toast", this.#startTimer, {signal: this.#abortController.signal});
183
+ root.addEventListener("hide.bs.toast", () => this.#stopTimer(), {signal: this.#abortController.signal});
184
+ root.addEventListener("show.bs.toast", () => this.#startTimer(), {signal: this.#abortController.signal});
183
185
 
184
186
  this.#toast = new BootstrapToast(root);
185
187
  if (this.open) this.show();
@@ -190,7 +192,7 @@ export class Toast extends HTMLElement {
190
192
  */
191
193
  disconnectedCallback(): void {
192
194
  this.#stopTimer();
193
- this.#abortController.abort();
195
+ this.#abortController?.abort();
194
196
  this.#toast.dispose();
195
197
  }
196
198
 
@@ -224,14 +226,16 @@ export class Toast extends HTMLElement {
224
226
  /**
225
227
  * Starts the timer.
226
228
  */
227
- readonly #startTimer: () => void = () =>
229
+ #startTimer(): void {
228
230
  this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000);
231
+ }
229
232
 
230
233
  /**
231
234
  * Stops the timer.
232
235
  */
233
- readonly #stopTimer: () => void = () =>
236
+ #stopTimer(): void {
234
237
  clearInterval(this.#timer);
238
+ }
235
239
 
236
240
  /**
237
241
  * Updates the value indicating whether to automatically hide this toast.
@@ -1,16 +0,0 @@
1
- import { Computed, Signal as State } from "@preact/signals-core";
2
- export { effect, type EffectOptions } from "@preact/signals-core";
3
- /**
4
- * Creates reactive primitives.
5
- */
6
- export declare class Signal {
7
- /**
8
- * Creates a new computed signal.
9
- */
10
- static readonly Computed: typeof Computed;
11
- /**
12
- * Creates a new plain signal.
13
- */
14
- static readonly State: typeof State;
15
- }
16
- //# sourceMappingURL=Signal.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Signal.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,EAAC,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAC,MAAM,EAAE,KAAK,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAEhE;;GAEG;AACH,qBAAa,MAAM;IAElB;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,kBAAY;IAEpC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,KAAK,eAAS;CAC9B"}
@@ -1,18 +0,0 @@
1
- import {Computed, Signal as State} from "@preact/signals-core";
2
- export {effect, type EffectOptions} from "@preact/signals-core";
3
-
4
- /**
5
- * Creates reactive primitives.
6
- */
7
- export class Signal { // eslint-disable-line @typescript-eslint/no-extraneous-class
8
-
9
- /**
10
- * Creates a new computed signal.
11
- */
12
- static readonly Computed = Computed;
13
-
14
- /**
15
- * Creates a new plain signal.
16
- */
17
- static readonly State = State;
18
- }