@cedx/base 0.25.0 → 0.27.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 (37) hide show
  1. package/ReadMe.md +1 -1
  2. package/lib/Date.d.ts +5 -0
  3. package/lib/Date.d.ts.map +1 -1
  4. package/lib/Date.js +14 -5
  5. package/lib/TimeSpan.d.ts +46 -0
  6. package/lib/TimeSpan.d.ts.map +1 -0
  7. package/lib/TimeSpan.js +45 -0
  8. package/lib/UI/Components/LoadingIndicator.d.ts.map +1 -1
  9. package/lib/UI/Components/LoadingIndicator.js +0 -2
  10. package/lib/UI/Components/TabActivator.d.ts +4 -0
  11. package/lib/UI/Components/TabActivator.d.ts.map +1 -1
  12. package/lib/UI/Components/TabActivator.js +10 -7
  13. package/lib/UI/Components/ThemeDropdown.d.ts.map +1 -1
  14. package/lib/UI/Components/ThemeDropdown.js +2 -2
  15. package/lib/UI/Components/Toast.d.ts.map +1 -1
  16. package/lib/UI/Components/Toast.js +16 -5
  17. package/lib/UI/Components/Toaster.d.ts.map +1 -1
  18. package/lib/UI/Components/Toaster.js +1 -1
  19. package/lib/UI/Components/TypeAhead.d.ts +53 -0
  20. package/lib/UI/Components/TypeAhead.d.ts.map +1 -0
  21. package/lib/UI/Components/TypeAhead.js +138 -0
  22. package/lib/UI/DialogResult.d.ts +0 -4
  23. package/lib/UI/DialogResult.d.ts.map +1 -1
  24. package/package.json +2 -2
  25. package/src/Client/Date.ts +15 -5
  26. package/src/Client/TimeSpan.ts +55 -0
  27. package/src/Client/UI/Components/LoadingIndicator.ts +0 -2
  28. package/src/Client/UI/Components/TabActivator.ts +11 -6
  29. package/src/Client/UI/Components/ThemeDropdown.ts +4 -3
  30. package/src/Client/UI/Components/Toast.ts +21 -5
  31. package/src/Client/UI/Components/Toaster.ts +4 -3
  32. package/src/Client/UI/Components/TypeAhead.ts +153 -0
  33. package/src/Client/UI/DialogResult.ts +0 -5
  34. package/lib/Duration.d.ts +0 -26
  35. package/lib/Duration.d.ts.map +0 -1
  36. package/lib/Duration.js +0 -21
  37. package/src/Client/Duration.ts +0 -30
package/ReadMe.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Cédric Belin's Base
2
- ![.NET](https://badgen.net/badge/.net/%3E%3D9.0/green) ![Version](https://badgen.net/badge/project/v0.25.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.27.0/blue) ![Licence](https://badgen.net/badge/licence/MIT/blue)
3
3
 
4
4
  Base library by [Cédric Belin](https://cedric-belin.fr), full stack developer,
5
5
  implemented in [C#](https://learn.microsoft.com/en-us/dotnet/csharp) and [TypeScript](https://www.typescriptlang.org).
package/lib/Date.d.ts CHANGED
@@ -52,6 +52,11 @@ export declare function isHoliday(date: Date): boolean;
52
52
  * @returns `true` if the specified date is a working day, otherwise `false`.
53
53
  */
54
54
  export declare function isWorkingDay(date: Date): boolean;
55
+ /**
56
+ * Gets the current date.
57
+ * @returns The current date.
58
+ */
59
+ export declare function today(): Date;
55
60
  /**
56
61
  * Converts the specified date to an ISO 8601 week.
57
62
  * @param date The date to convert.
package/lib/Date.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Date.d.ts","sourceRoot":"","sources":["../src/Client/Date.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAE3C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAc1C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAqB9C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAIhD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAG9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAG7C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAGhD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAM,GAAG,MAAM,CAM7H"}
1
+ {"version":3,"file":"Date.d.ts","sourceRoot":"","sources":["../src/Client/Date.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAE3C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAc1C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAqB9C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAIhD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAG9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAG7C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAGhD;AAED;;;GAGG;AACH,wBAAgB,KAAK,IAAI,IAAI,CAI5B;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAM,GAAG,MAAM,CAM7H"}
package/lib/Date.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Duration } from "./Duration.js";
1
+ import { TimeSpan } from "./TimeSpan.js";
2
2
  /**
3
3
  * Returns the date at midnight corresponding to the specified date.
4
4
  * @param date The source date.
@@ -52,9 +52,9 @@ export function getHolidays(date) {
52
52
  holidays.push(new Date(year, 11, 25)); // Christmas.
53
53
  // Holidays depending on Easter.
54
54
  const easter = getEaster(date);
55
- holidays.push(new Date(easter.getTime() + Duration.Day)); // Easter monday.
56
- holidays.push(new Date(easter.getTime() + (39 * Duration.Day))); // Ascension thursday.
57
- holidays.push(new Date(easter.getTime() + (50 * Duration.Day))); // Pentecost monday.
55
+ holidays.push(new Date(easter.getTime() + TimeSpan.MillisecondsPerDay)); // Easter monday.
56
+ holidays.push(new Date(easter.getTime() + (39 * TimeSpan.MillisecondsPerDay))); // Ascension thursday.
57
+ holidays.push(new Date(easter.getTime() + (50 * TimeSpan.MillisecondsPerDay))); // Pentecost monday.
58
58
  return holidays;
59
59
  }
60
60
  /**
@@ -73,7 +73,7 @@ export function getQuarter(date) {
73
73
  export function getWeekOfYear(date) {
74
74
  const thursday = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 3 - ((date.getDay() + 6) % 7));
75
75
  const firstWeek = new Date(thursday.getFullYear(), 0, 4);
76
- return 1 + Math.round((((thursday.getTime() - firstWeek.getTime()) / Duration.Day) - 3 + ((firstWeek.getDay() + 6) % 7)) / 7);
76
+ return 1 + Math.round((((thursday.getTime() - firstWeek.getTime()) / TimeSpan.MillisecondsPerDay) - 3 + ((firstWeek.getDay() + 6) % 7)) / 7);
77
77
  }
78
78
  /**
79
79
  * Returns a value indicating whether the specified date is in a leap year.
@@ -102,6 +102,15 @@ export function isWorkingDay(date) {
102
102
  const dayOfWeek = date.getDay();
103
103
  return dayOfWeek >= 1 && dayOfWeek <= 5;
104
104
  }
105
+ /**
106
+ * Gets the current date.
107
+ * @returns The current date.
108
+ */
109
+ export function today() {
110
+ const date = new Date;
111
+ date.setHours(0, 0, 0, 0);
112
+ return date;
113
+ }
105
114
  /**
106
115
  * Converts the specified date to an ISO 8601 week.
107
116
  * @param date The date to convert.
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Provides some common time intervals in milliseconds.
3
+ */
4
+ export declare const TimeSpan: Readonly<{
5
+ /**
6
+ * The number of hours in 1 day.
7
+ */
8
+ HoursPerDay: 24;
9
+ /**
10
+ * The number of minutes in 1 day.
11
+ */
12
+ MinutesPerDay: 1440;
13
+ /**
14
+ * The number of minutes in 1 hour.
15
+ */
16
+ MinutesPerHour: 60;
17
+ /**
18
+ * The number of seconds in 1 day.
19
+ */
20
+ SecondsPerDay: 86400;
21
+ /**
22
+ * The number of seconds in 1 hour.
23
+ */
24
+ SecondsPerHour: 3600;
25
+ /**
26
+ * The number of seconds in 1 minute.
27
+ */
28
+ SecondsPerMinute: 60;
29
+ /**
30
+ * The number of milliseconds in 1 day.
31
+ */
32
+ MillisecondsPerDay: 86400000;
33
+ /**
34
+ * The number of milliseconds in 1 hour.
35
+ */
36
+ MillisecondsPerHour: 3600000;
37
+ /**
38
+ * The number of milliseconds in 1 minute.
39
+ */
40
+ MillisecondsPerMinute: 60000;
41
+ /**
42
+ * The number of milliseconds in 1 second.
43
+ */
44
+ MillisecondsPerSecond: 1000;
45
+ }>;
46
+ //# sourceMappingURL=TimeSpan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeSpan.d.ts","sourceRoot":"","sources":["../src/Client/TimeSpan.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,QAAQ;IAEpB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Provides some common time intervals in milliseconds.
3
+ */
4
+ export const TimeSpan = Object.freeze({
5
+ /**
6
+ * The number of hours in 1 day.
7
+ */
8
+ HoursPerDay: 24,
9
+ /**
10
+ * The number of minutes in 1 day.
11
+ */
12
+ MinutesPerDay: 1_440,
13
+ /**
14
+ * The number of minutes in 1 hour.
15
+ */
16
+ MinutesPerHour: 60,
17
+ /**
18
+ * The number of seconds in 1 day.
19
+ */
20
+ SecondsPerDay: 86_400,
21
+ /**
22
+ * The number of seconds in 1 hour.
23
+ */
24
+ SecondsPerHour: 3_600,
25
+ /**
26
+ * The number of seconds in 1 minute.
27
+ */
28
+ SecondsPerMinute: 60,
29
+ /**
30
+ * The number of milliseconds in 1 day.
31
+ */
32
+ MillisecondsPerDay: 86_400_000,
33
+ /**
34
+ * The number of milliseconds in 1 hour.
35
+ */
36
+ MillisecondsPerHour: 3_600_000,
37
+ /**
38
+ * The number of milliseconds in 1 minute.
39
+ */
40
+ MillisecondsPerMinute: 60_000,
41
+ /**
42
+ * The number of milliseconds in 1 second.
43
+ */
44
+ MillisecondsPerSecond: 1_000
45
+ });
@@ -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,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;IAU3C;;OAEG;IACH,IAAI,IAAI,IAAI;CAcZ;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,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"}
@@ -66,7 +66,6 @@ export class LoadingIndicator extends HTMLElement {
66
66
  this.#requestCount = 0;
67
67
  this.classList.add("hide");
68
68
  this.classList.remove("show");
69
- document.body.classList.remove("loading");
70
69
  }
71
70
  }
72
71
  /**
@@ -76,7 +75,6 @@ export class LoadingIndicator extends HTMLElement {
76
75
  this.#requestCount++;
77
76
  this.classList.remove("hide");
78
77
  this.classList.add("show");
79
- document.body.classList.add("loading");
80
78
  }
81
79
  /**
82
80
  * Updates the value indicating whether to apply a transition.
@@ -3,6 +3,10 @@ import { StorageArea } from "../StorageArea.js";
3
3
  * A component that activates a tab, based on its index saved in the web storage.
4
4
  */
5
5
  export declare class TabActivator extends HTMLElement {
6
+ /**
7
+ * Creates a new tab activator.
8
+ */
9
+ constructor();
6
10
  /**
7
11
  * The index of the active tab.
8
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TabActivator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/TabActivator.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAE9C;;GAEG;AACH,qBAAa,YAAa,SAAQ,WAAW;IAS5C;;OAEG;IACH,IAAI,cAAc,IAAI,MAAM,CAG3B;IACD,IAAI,cAAc,CAAC,KAAK,EAAE,MAAM,EAE/B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,UAAU,CAAC,OAAO,CAEhC;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,WAAW,CAG7B;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,WAAW,EAEjC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAGvB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,UAAU,CAAC,WAAW,CAAC,CAElC;IAED;;OAEG;IACH,iBAAiB,IAAI,IAAI;CAQzB;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,eAAe,EAAE,YAAY,CAAC;KAC9B;CACD"}
1
+ {"version":3,"file":"TabActivator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/TabActivator.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAE9C;;GAEG;AACH,qBAAa,YAAa,SAAQ,WAAW;IAE5C;;OAEG;;IAeH;;OAEG;IACH,IAAI,cAAc,IAAI,MAAM,CAG3B;IACD,IAAI,cAAc,CAAC,KAAK,EAAE,MAAM,EAE/B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,UAAU,CAAC,OAAO,CAEhC;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,WAAW,CAG7B;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,WAAW,EAEjC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAGvB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,UAAU,CAAC,WAAW,CAAC,CAElC;IAED;;OAEG;IACH,iBAAiB,IAAI,IAAI;CAGzB;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,eAAe,EAAE,YAAY,CAAC;KAC9B;CACD"}
@@ -4,6 +4,15 @@ import { StorageArea } from "../StorageArea.js";
4
4
  * A component that activates a tab, based on its index saved in the web storage.
5
5
  */
6
6
  export class TabActivator extends HTMLElement {
7
+ /**
8
+ * Creates a new tab activator.
9
+ */
10
+ constructor() {
11
+ super();
12
+ const { tabs } = this;
13
+ for (let index = 0; index < tabs.length; index++)
14
+ tabs.item(index).addEventListener("show.bs.tab", () => this.activeTabIndex = index);
15
+ }
7
16
  /**
8
17
  * Registers the component.
9
18
  */
@@ -56,12 +65,6 @@ export class TabActivator extends HTMLElement {
56
65
  * Method invoked when this component is connected.
57
66
  */
58
67
  connectedCallback() {
59
- const { activeTabIndex, tabs } = this;
60
- for (let index = 0; index < tabs.length; index++) {
61
- const tab = tabs.item(index);
62
- tab.addEventListener("click", () => this.activeTabIndex = index);
63
- if (index == activeTabIndex)
64
- Tab.getOrCreateInstance(tab).show();
65
- }
68
+ Tab.getOrCreateInstance(this.tabs.item(this.activeTabIndex)).show();
66
69
  }
67
70
  }
@@ -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,EAAU,MAAM,gBAAgB,CAAC;AAEjD;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAsC;IAYxE;;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,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;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAQzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,IAAI,IAAI,IAAI;CAgDZ;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,EAAU,MAAM,gBAAgB,CAAC;AAEjD;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAsC;IAYxE;;OAEG;;IAcH;;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,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;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAQzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,IAAI,IAAI,IAAI;CAgDZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,aAAa,CAAC;KAChC;CACD"}
@@ -141,7 +141,7 @@ export class ThemeDropdown extends HTMLElement {
141
141
  */
142
142
  #setAppTheme(event) {
143
143
  event.preventDefault();
144
- this.appTheme = event.currentTarget.dataset.theme;
144
+ this.appTheme = event.currentTarget.value;
145
145
  this.save();
146
146
  }
147
147
  /**
@@ -157,7 +157,7 @@ export class ThemeDropdown extends HTMLElement {
157
157
  */
158
158
  #updateAppTheme(value) {
159
159
  this.querySelector(".dropdown-toggle > .icon").textContent = getIcon(value);
160
- this.querySelector(`button[data-theme="${value}"]`).appendChild(this.querySelector(".dropdown-item > .icon"));
160
+ this.querySelector(`.dropdown-menu button[value="${value}"]`).appendChild(this.querySelector(".dropdown-item > .icon"));
161
161
  this.#applyToDocument();
162
162
  }
163
163
  /**
@@ -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;IAkC5G;;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;IAK5B;;OAEG;IACH,IAAI,IAAI,IAAI;CAwFZ;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;IAkC5G;;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;IAS5B;;OAEG;IACH,IAAI,IAAI,IAAI;CAoGZ;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,cAAc,EAAE,KAAK,CAAC;KACtB;CACD"}
@@ -168,10 +168,10 @@ export class Toast extends HTMLElement {
168
168
  * Method invoked when this component is connected.
169
169
  */
170
170
  connectedCallback() {
171
- const toast = this.firstElementChild;
172
- toast.addEventListener("hide.bs.toast", () => clearInterval(this.#timer));
173
- toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000));
174
- this.#toast = new BootstrapToast(toast);
171
+ const root = this.firstElementChild;
172
+ root.addEventListener("hide.bs.toast", this.#stopTimer);
173
+ root.addEventListener("show.bs.toast", this.#startTimer);
174
+ this.#toast = new BootstrapToast(root);
175
175
  if (this.open)
176
176
  this.show();
177
177
  }
@@ -179,7 +179,10 @@ export class Toast extends HTMLElement {
179
179
  * Method invoked when this component is disconnected.
180
180
  */
181
181
  disconnectedCallback() {
182
- clearInterval(this.#timer);
182
+ const root = this.firstElementChild;
183
+ root.removeEventListener("hide.bs.toast", () => this.#stopTimer);
184
+ root.removeEventListener("show.bs.toast", () => this.#startTimer);
185
+ this.#stopTimer();
183
186
  this.#toast.dispose();
184
187
  }
185
188
  /**
@@ -205,6 +208,14 @@ export class Toast extends HTMLElement {
205
208
  }
206
209
  return this.#formatter.format(Math.ceil(-elapsed), Toast.#timeUnits[index]);
207
210
  }
211
+ /**
212
+ * Starts the timer.
213
+ */
214
+ #startTimer = () => this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000);
215
+ /**
216
+ * Stops the timer.
217
+ */
218
+ #stopTimer = () => clearInterval(this.#timer);
208
219
  /**
209
220
  * Updates the value indicating whether to automatically hide this toast.
210
221
  * @param value The new value.
@@ -1 +1 @@
1
- {"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/Toaster.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,MAAM;IAEtB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,IAAI,EAAE,gBAAgB,CAAC;IAEvB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;IAEtB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,OAAQ,SAAQ,WAAW;;IAEvC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAgB;IAOlD;;OAEG;;IAaH;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAGrB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,CAGzB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAE7B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,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,QAAQ,IAAI,QAAQ,CAGvB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAE3B;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAO/F;;;;;OAKG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAI1E;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CA4BzB;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,OAAO,CAAC;KAC7B;CACD"}
1
+ {"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/Toaster.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,MAAM;IAEtB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,IAAI,EAAE,gBAAgB,CAAC;IAEvB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;IAEtB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,OAAQ,SAAQ,WAAW;;IAEvC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAgB;IAOlD;;OAEG;;IAcH;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAGrB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,CAGzB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAE7B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,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,QAAQ,IAAI,QAAQ,CAGvB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAE3B;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAO/F;;;;;OAKG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAI1E;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CA4BzB;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,OAAO,CAAC;KAC7B;CACD"}
@@ -60,7 +60,7 @@ export class Toaster extends HTMLElement {
60
60
  */
61
61
  get delay() {
62
62
  const value = Number(this.getAttribute("delay"));
63
- return Math.max(1, Number.isNaN(value) ? 5_000 : value);
63
+ return Math.max(0, Number.isNaN(value) ? 5_000 : value);
64
64
  }
65
65
  set delay(value) {
66
66
  this.setAttribute("delay", value.toString());
@@ -0,0 +1,53 @@
1
+ /**
2
+ * A component that moves back in the session history when clicked.
3
+ */
4
+ export declare class TypeAhead extends HTMLElement {
5
+ #private;
6
+ /**
7
+ * The list of observed attributes.
8
+ */
9
+ static readonly observedAttributes: string[];
10
+ /**
11
+ * The function invoked when the query has been changed.
12
+ */
13
+ set handler(callback: (query: string) => Promise<string[]>);
14
+ /**
15
+ * The data list identifier.
16
+ */
17
+ get list(): string;
18
+ set list(value: string);
19
+ /**
20
+ * The minimum character length needed before triggering autocomplete suggestions.
21
+ */
22
+ get minLength(): number;
23
+ set minLength(value: number);
24
+ /**
25
+ * The query to look up.
26
+ */
27
+ get query(): string;
28
+ set query(value: string);
29
+ /**
30
+ * The delay in milliseconds to wait before triggering autocomplete suggestions.
31
+ */
32
+ get wait(): number;
33
+ set wait(value: number);
34
+ /**
35
+ * Method invoked when an attribute has been changed.
36
+ * @param attribute The attribute name.
37
+ * @param oldValue The previous attribute value.
38
+ * @param newValue The new attribute value.
39
+ */
40
+ attributeChangedCallback(attribute: string, oldValue: string | null, newValue: string | null): void;
41
+ }
42
+ /**
43
+ * Declaration merging.
44
+ */
45
+ declare global {
46
+ /**
47
+ * The map of HTML tag names.
48
+ */
49
+ interface HTMLElementTagNameMap {
50
+ "type-ahead": TypeAhead;
51
+ }
52
+ }
53
+ //# sourceMappingURL=TypeAhead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TypeAhead.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/TypeAhead.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,SAAU,SAAQ,WAAW;;IAEzC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAAqB;IAmBvD;;OAEG;IACH,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,EAKzD;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAGtB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,EAE1B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;CAsD/F;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,YAAY,EAAE,SAAS,CAAC;KACxB;CACD"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * A component that moves back in the session history when clicked.
3
+ */
4
+ export class TypeAhead extends HTMLElement {
5
+ /**
6
+ * The list of observed attributes.
7
+ */
8
+ static observedAttributes = ["list", "query"];
9
+ /**
10
+ * The debounced handler used to look up the query.
11
+ */
12
+ #debounced = () => { };
13
+ /**
14
+ * The previous query.
15
+ */
16
+ #previousQuery = "";
17
+ /**
18
+ * Registers the component.
19
+ */
20
+ static {
21
+ customElements.define("type-ahead", this);
22
+ }
23
+ /**
24
+ * The function invoked when the query has been changed.
25
+ */
26
+ set handler(callback) {
27
+ this.#debounced = this.#debounce(async (query) => {
28
+ try {
29
+ this.#updateItems(await callback(query));
30
+ }
31
+ catch {
32
+ this.#updateItems([]);
33
+ }
34
+ }, this.wait);
35
+ }
36
+ /**
37
+ * The data list identifier.
38
+ */
39
+ get list() {
40
+ return (this.getAttribute("list") ?? "").trim();
41
+ }
42
+ set list(value) {
43
+ this.setAttribute("list", value);
44
+ }
45
+ /**
46
+ * The minimum character length needed before triggering autocomplete suggestions.
47
+ */
48
+ get minLength() {
49
+ const value = Number(this.getAttribute("minLength"));
50
+ return Math.max(1, Number.isNaN(value) ? 1 : value);
51
+ }
52
+ set minLength(value) {
53
+ this.setAttribute("minLength", value.toString());
54
+ }
55
+ /**
56
+ * The query to look up.
57
+ */
58
+ get query() {
59
+ return (this.getAttribute("query") ?? "").trim();
60
+ }
61
+ set query(value) {
62
+ this.setAttribute("query", value);
63
+ }
64
+ /**
65
+ * The delay in milliseconds to wait before triggering autocomplete suggestions.
66
+ */
67
+ get wait() {
68
+ const value = Number(this.getAttribute("wait"));
69
+ return Math.max(0, Number.isNaN(value) ? 300 : value);
70
+ }
71
+ set wait(value) {
72
+ this.setAttribute("wait", value.toString());
73
+ }
74
+ /**
75
+ * Method invoked when an attribute has been changed.
76
+ * @param attribute The attribute name.
77
+ * @param oldValue The previous attribute value.
78
+ * @param newValue The new attribute value.
79
+ */
80
+ attributeChangedCallback(attribute, oldValue, newValue) {
81
+ if (newValue != oldValue)
82
+ switch (attribute) {
83
+ case "list":
84
+ this.#updateList(newValue ?? "");
85
+ break;
86
+ case "query":
87
+ this.#updateQuery(newValue ?? "");
88
+ break;
89
+ // No default
90
+ }
91
+ }
92
+ /**
93
+ * Postpones the invocation of the specified callback until after a given delay has elapsed since the last time it was invoked.
94
+ * @param callback The function to debounce.
95
+ * @param delay The delay to wait, in milliseconds.
96
+ * @returns The debounced function.
97
+ */
98
+ #debounce(callback, delay) {
99
+ let timer = 0;
100
+ return value => {
101
+ if (timer)
102
+ clearTimeout(timer);
103
+ timer = window.setTimeout(callback, delay, value);
104
+ };
105
+ }
106
+ /**
107
+ * Updates the identifier of the underlying data list.
108
+ * @param value The new value.
109
+ */
110
+ #updateList(value) {
111
+ this.firstElementChild.id = value.trim();
112
+ }
113
+ /**
114
+ * Updates the query to look up.
115
+ * @param value The new value.
116
+ */
117
+ #updateQuery(value) {
118
+ const query = value.trim();
119
+ if (query != this.#previousQuery) {
120
+ this.#previousQuery = query;
121
+ if (query.length < this.minLength)
122
+ this.#updateItems([]);
123
+ else
124
+ this.#debounced(query);
125
+ }
126
+ }
127
+ /**
128
+ * Updates the items of the underlying data list.
129
+ * @param values The new values.
130
+ */
131
+ #updateItems(values) {
132
+ this.firstElementChild.replaceChildren(...values.map(value => {
133
+ const option = document.createElement("option");
134
+ option.value = value;
135
+ return option;
136
+ }));
137
+ }
138
+ }
@@ -27,8 +27,4 @@ export declare const DialogResult: Readonly<{
27
27
  */
28
28
  Ignore: "Ignore";
29
29
  }>;
30
- /**
31
- * Specifies the return value of a dialog box.
32
- */
33
- export type DialogResult = typeof DialogResult[keyof typeof DialogResult];
34
30
  //# sourceMappingURL=DialogResult.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DialogResult.d.ts","sourceRoot":"","sources":["../../src/Client/UI/DialogResult.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,YAAY;IAExB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"DialogResult.d.ts","sourceRoot":"","sources":["../../src/Client/UI/DialogResult.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,YAAY;IAExB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC"}
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.25.0",
10
+ "version": "0.27.0",
11
11
  "devDependencies": {
12
12
  "@playwright/browser-chromium": "^1.55.0",
13
13
  "@types/bootstrap": "^5.2.10",
@@ -21,7 +21,7 @@
21
21
  "mocha": "^11.7.1",
22
22
  "playwright": "^1.55.0",
23
23
  "serve-handler": "^6.1.6",
24
- "typedoc": "^0.28.11",
24
+ "typedoc": "^0.28.12",
25
25
  "typescript": "^5.9.2",
26
26
  "typescript-eslint": "^8.41.0"
27
27
  },
@@ -1,4 +1,4 @@
1
- import {Duration} from "./Duration.js";
1
+ import {TimeSpan} from "./TimeSpan.js";
2
2
 
3
3
  /**
4
4
  * Returns the date at midnight corresponding to the specified date.
@@ -60,9 +60,9 @@ export function getHolidays(date: Date): Date[] {
60
60
 
61
61
  // Holidays depending on Easter.
62
62
  const easter = getEaster(date);
63
- holidays.push(new Date(easter.getTime() + Duration.Day)); // Easter monday.
64
- holidays.push(new Date(easter.getTime() + (39 * Duration.Day))); // Ascension thursday.
65
- holidays.push(new Date(easter.getTime() + (50 * Duration.Day))); // Pentecost monday.
63
+ holidays.push(new Date(easter.getTime() + TimeSpan.MillisecondsPerDay)); // Easter monday.
64
+ holidays.push(new Date(easter.getTime() + (39 * TimeSpan.MillisecondsPerDay))); // Ascension thursday.
65
+ holidays.push(new Date(easter.getTime() + (50 * TimeSpan.MillisecondsPerDay))); // Pentecost monday.
66
66
 
67
67
  return holidays;
68
68
  }
@@ -84,7 +84,7 @@ export function getQuarter(date: Date): number {
84
84
  export function getWeekOfYear(date: Date): number {
85
85
  const thursday = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 3 - ((date.getDay() + 6) % 7));
86
86
  const firstWeek = new Date(thursday.getFullYear(), 0, 4);
87
- return 1 + Math.round((((thursday.getTime() - firstWeek.getTime()) / Duration.Day) - 3 + ((firstWeek.getDay() + 6) % 7)) / 7);
87
+ return 1 + Math.round((((thursday.getTime() - firstWeek.getTime()) / TimeSpan.MillisecondsPerDay) - 3 + ((firstWeek.getDay() + 6) % 7)) / 7);
88
88
  }
89
89
 
90
90
  /**
@@ -117,6 +117,16 @@ export function isWorkingDay(date: Date): boolean {
117
117
  return dayOfWeek >= 1 && dayOfWeek <= 5;
118
118
  }
119
119
 
120
+ /**
121
+ * Gets the current date.
122
+ * @returns The current date.
123
+ */
124
+ export function today(): Date {
125
+ const date = new Date;
126
+ date.setHours(0, 0, 0, 0);
127
+ return date;
128
+ }
129
+
120
130
  /**
121
131
  * Converts the specified date to an ISO 8601 week.
122
132
  * @param date The date to convert.
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Provides some common time intervals in milliseconds.
3
+ */
4
+ export const TimeSpan = Object.freeze({
5
+
6
+ /**
7
+ * The number of hours in 1 day.
8
+ */
9
+ HoursPerDay: 24,
10
+
11
+ /**
12
+ * The number of minutes in 1 day.
13
+ */
14
+ MinutesPerDay: 1_440,
15
+
16
+ /**
17
+ * The number of minutes in 1 hour.
18
+ */
19
+ MinutesPerHour: 60,
20
+
21
+ /**
22
+ * The number of seconds in 1 day.
23
+ */
24
+ SecondsPerDay: 86_400,
25
+
26
+ /**
27
+ * The number of seconds in 1 hour.
28
+ */
29
+ SecondsPerHour: 3_600,
30
+
31
+ /**
32
+ * The number of seconds in 1 minute.
33
+ */
34
+ SecondsPerMinute: 60,
35
+
36
+ /**
37
+ * The number of milliseconds in 1 day.
38
+ */
39
+ MillisecondsPerDay: 86_400_000,
40
+
41
+ /**
42
+ * The number of milliseconds in 1 hour.
43
+ */
44
+ MillisecondsPerHour: 3_600_000,
45
+
46
+ /**
47
+ * The number of milliseconds in 1 minute.
48
+ */
49
+ MillisecondsPerMinute: 60_000,
50
+
51
+ /**
52
+ * The number of milliseconds in 1 second.
53
+ */
54
+ MillisecondsPerSecond: 1_000
55
+ });
@@ -70,7 +70,6 @@ export class LoadingIndicator extends HTMLElement {
70
70
  this.#requestCount = 0;
71
71
  this.classList.add("hide");
72
72
  this.classList.remove("show");
73
- document.body.classList.remove("loading");
74
73
  }
75
74
  }
76
75
 
@@ -81,7 +80,6 @@ export class LoadingIndicator extends HTMLElement {
81
80
  this.#requestCount++;
82
81
  this.classList.remove("hide");
83
82
  this.classList.add("show");
84
- document.body.classList.add("loading");
85
83
  }
86
84
 
87
85
  /**
@@ -6,6 +6,16 @@ import {StorageArea} from "../StorageArea.js";
6
6
  */
7
7
  export class TabActivator extends HTMLElement {
8
8
 
9
+ /**
10
+ * Creates a new tab activator.
11
+ */
12
+ constructor() {
13
+ super();
14
+ const {tabs} = this;
15
+ for (let index = 0; index < tabs.length; index++)
16
+ tabs.item(index).addEventListener("show.bs.tab", () => this.activeTabIndex = index);
17
+ }
18
+
9
19
  /**
10
20
  * Registers the component.
11
21
  */
@@ -64,12 +74,7 @@ export class TabActivator extends HTMLElement {
64
74
  * Method invoked when this component is connected.
65
75
  */
66
76
  connectedCallback(): void {
67
- const {activeTabIndex, tabs} = this;
68
- for (let index = 0; index < tabs.length; index++) {
69
- const tab = tabs.item(index);
70
- tab.addEventListener("click", () => this.activeTabIndex = index);
71
- if (index == activeTabIndex) Tab.getOrCreateInstance(tab).show();
72
- }
77
+ Tab.getOrCreateInstance(this.tabs.item(this.activeTabIndex)).show();
73
78
  }
74
79
  }
75
80
 
@@ -27,7 +27,8 @@ export class ThemeDropdown extends HTMLElement {
27
27
  */
28
28
  constructor() {
29
29
  super();
30
- for (const button of this.querySelectorAll(".dropdown-menu button")) button.addEventListener("click", this.#setAppTheme.bind(this));
30
+ for (const button of this.querySelectorAll(".dropdown-menu button"))
31
+ button.addEventListener("click", this.#setAppTheme.bind(this));
31
32
  }
32
33
 
33
34
  /**
@@ -151,7 +152,7 @@ export class ThemeDropdown extends HTMLElement {
151
152
  */
152
153
  #setAppTheme(event: Event): void {
153
154
  event.preventDefault();
154
- this.appTheme = (event.currentTarget as HTMLElement).dataset.theme! as AppTheme;
155
+ this.appTheme = (event.currentTarget as HTMLButtonElement).value as AppTheme;
155
156
  this.save();
156
157
  }
157
158
 
@@ -169,7 +170,7 @@ export class ThemeDropdown extends HTMLElement {
169
170
  */
170
171
  #updateAppTheme(value: AppTheme): void {
171
172
  this.querySelector(".dropdown-toggle > .icon")!.textContent = getIcon(value);
172
- this.querySelector(`button[data-theme="${value}"]`)!.appendChild(this.querySelector(".dropdown-item > .icon")!);
173
+ this.querySelector(`.dropdown-menu button[value="${value}"]`)!.appendChild(this.querySelector(".dropdown-item > .icon")!);
173
174
  this.#applyToDocument();
174
175
  }
175
176
 
@@ -172,11 +172,11 @@ export class Toast extends HTMLElement {
172
172
  * Method invoked when this component is connected.
173
173
  */
174
174
  connectedCallback(): void {
175
- const toast = this.firstElementChild!;
176
- toast.addEventListener("hide.bs.toast", () => clearInterval(this.#timer));
177
- toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000));
175
+ const root = this.firstElementChild!;
176
+ root.addEventListener("hide.bs.toast", this.#stopTimer);
177
+ root.addEventListener("show.bs.toast", this.#startTimer);
178
178
 
179
- this.#toast = new BootstrapToast(toast);
179
+ this.#toast = new BootstrapToast(root);
180
180
  if (this.open) this.show();
181
181
  }
182
182
 
@@ -184,7 +184,11 @@ export class Toast extends HTMLElement {
184
184
  * Method invoked when this component is disconnected.
185
185
  */
186
186
  disconnectedCallback(): void {
187
- clearInterval(this.#timer);
187
+ const root = this.firstElementChild!;
188
+ root.removeEventListener("hide.bs.toast", () => this.#stopTimer);
189
+ root.removeEventListener("show.bs.toast", () => this.#startTimer);
190
+
191
+ this.#stopTimer();
188
192
  this.#toast.dispose();
189
193
  }
190
194
 
@@ -215,6 +219,18 @@ export class Toast extends HTMLElement {
215
219
  return this.#formatter.format(Math.ceil(-elapsed), Toast.#timeUnits[index]);
216
220
  }
217
221
 
222
+ /**
223
+ * Starts the timer.
224
+ */
225
+ readonly #startTimer: () => void = () =>
226
+ this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000);
227
+
228
+ /**
229
+ * Stops the timer.
230
+ */
231
+ readonly #stopTimer: () => void = () =>
232
+ clearInterval(this.#timer);
233
+
218
234
  /**
219
235
  * Updates the value indicating whether to automatically hide this toast.
220
236
  * @param value The new value.
@@ -60,14 +60,15 @@ export class Toaster extends HTMLElement {
60
60
  /**
61
61
  * The template for a toast.
62
62
  */
63
- readonly #toastTemplate: DocumentFragment = this.querySelector("template")!.content;
63
+ readonly #toastTemplate = this.querySelector("template")!.content;
64
64
 
65
65
  /**
66
66
  * Creates a new toaster.
67
67
  */
68
68
  constructor() {
69
69
  super();
70
- for (const toast of this.querySelectorAll("toaster-item")) toast.addEventListener("hidden.bs.toast", () => toast.remove());
70
+ for (const toast of this.querySelectorAll("toaster-item"))
71
+ toast.addEventListener("hidden.bs.toast", () => toast.remove());
71
72
  }
72
73
 
73
74
  /**
@@ -114,7 +115,7 @@ export class Toaster extends HTMLElement {
114
115
  */
115
116
  get delay(): number {
116
117
  const value = Number(this.getAttribute("delay"));
117
- return Math.max(1, Number.isNaN(value) ? 5_000 : value);
118
+ return Math.max(0, Number.isNaN(value) ? 5_000 : value);
118
119
  }
119
120
  set delay(value: number) {
120
121
  this.setAttribute("delay", value.toString());
@@ -0,0 +1,153 @@
1
+ /**
2
+ * A component that moves back in the session history when clicked.
3
+ */
4
+ export class TypeAhead extends HTMLElement {
5
+
6
+ /**
7
+ * The list of observed attributes.
8
+ */
9
+ static readonly observedAttributes = ["list", "query"];
10
+
11
+ /**
12
+ * The debounced handler used to look up the query.
13
+ */
14
+ #debounced: (value: string) => void = () => { /* Noop */ };
15
+
16
+ /**
17
+ * The previous query.
18
+ */
19
+ #previousQuery = "";
20
+
21
+ /**
22
+ * Registers the component.
23
+ */
24
+ static {
25
+ customElements.define("type-ahead", this);
26
+ }
27
+
28
+ /**
29
+ * The function invoked when the query has been changed.
30
+ */
31
+ set handler(callback: (query: string) => Promise<string[]>) { // eslint-disable-line accessor-pairs
32
+ this.#debounced = this.#debounce(async query => { // eslint-disable-line @typescript-eslint/no-misused-promises
33
+ try { this.#updateItems(await callback(query)); }
34
+ catch { this.#updateItems([]); }
35
+ }, this.wait);
36
+ }
37
+
38
+ /**
39
+ * The data list identifier.
40
+ */
41
+ get list(): string {
42
+ return (this.getAttribute("list") ?? "").trim();
43
+ }
44
+ set list(value: string) {
45
+ this.setAttribute("list", value);
46
+ }
47
+
48
+ /**
49
+ * The minimum character length needed before triggering autocomplete suggestions.
50
+ */
51
+ get minLength(): number {
52
+ const value = Number(this.getAttribute("minLength"));
53
+ return Math.max(1, Number.isNaN(value) ? 1 : value);
54
+ }
55
+ set minLength(value: number) {
56
+ this.setAttribute("minLength", value.toString());
57
+ }
58
+
59
+ /**
60
+ * The query to look up.
61
+ */
62
+ get query(): string {
63
+ return (this.getAttribute("query") ?? "").trim();
64
+ }
65
+ set query(value: string) {
66
+ this.setAttribute("query", value);
67
+ }
68
+
69
+ /**
70
+ * The delay in milliseconds to wait before triggering autocomplete suggestions.
71
+ */
72
+ get wait(): number {
73
+ const value = Number(this.getAttribute("wait"));
74
+ return Math.max(0, Number.isNaN(value) ? 300 : value);
75
+ }
76
+ set wait(value: number) {
77
+ this.setAttribute("wait", value.toString());
78
+ }
79
+
80
+ /**
81
+ * Method invoked when an attribute has been changed.
82
+ * @param attribute The attribute name.
83
+ * @param oldValue The previous attribute value.
84
+ * @param newValue The new attribute value.
85
+ */
86
+ attributeChangedCallback(attribute: string, oldValue: string|null, newValue: string|null): void {
87
+ if (newValue != oldValue) switch (attribute) {
88
+ case "list": this.#updateList(newValue ?? ""); break;
89
+ case "query": this.#updateQuery(newValue ?? ""); break;
90
+ // No default
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Postpones the invocation of the specified callback until after a given delay has elapsed since the last time it was invoked.
96
+ * @param callback The function to debounce.
97
+ * @param delay The delay to wait, in milliseconds.
98
+ * @returns The debounced function.
99
+ */
100
+ #debounce(callback: (value: string) => void, delay: number): (value: string) => void {
101
+ let timer = 0;
102
+ return value => {
103
+ if (timer) clearTimeout(timer);
104
+ timer = window.setTimeout(callback, delay, value);
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Updates the identifier of the underlying data list.
110
+ * @param value The new value.
111
+ */
112
+ #updateList(value: string): void {
113
+ this.firstElementChild!.id = value.trim();
114
+ }
115
+
116
+ /**
117
+ * Updates the query to look up.
118
+ * @param value The new value.
119
+ */
120
+ #updateQuery(value: string): void {
121
+ const query = value.trim();
122
+ if (query != this.#previousQuery) {
123
+ this.#previousQuery = query;
124
+ if (query.length < this.minLength) this.#updateItems([]);
125
+ else this.#debounced(query);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Updates the items of the underlying data list.
131
+ * @param values The new values.
132
+ */
133
+ #updateItems(values: string[]): void {
134
+ this.firstElementChild!.replaceChildren(...values.map(value => {
135
+ const option = document.createElement("option");
136
+ option.value = value;
137
+ return option;
138
+ }));
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Declaration merging.
144
+ */
145
+ declare global {
146
+
147
+ /**
148
+ * The map of HTML tag names.
149
+ */
150
+ interface HTMLElementTagNameMap {
151
+ "type-ahead": TypeAhead;
152
+ }
153
+ }
@@ -33,8 +33,3 @@ export const DialogResult = Object.freeze({
33
33
  */
34
34
  Ignore: "Ignore"
35
35
  });
36
-
37
- /**
38
- * Specifies the return value of a dialog box.
39
- */
40
- export type DialogResult = typeof DialogResult[keyof typeof DialogResult];
package/lib/Duration.d.ts DELETED
@@ -1,26 +0,0 @@
1
- /**
2
- * Provides some common durations in milliseconds.
3
- */
4
- export declare const Duration: Readonly<{
5
- /**
6
- * One second.
7
- */
8
- Second: 1000;
9
- /**
10
- * One minute.
11
- */
12
- Minute: 60000;
13
- /**
14
- * One hour.
15
- */
16
- Hour: 3600000;
17
- /**
18
- * One day.
19
- */
20
- Day: 86400000;
21
- }>;
22
- /**
23
- * Provides some common durations in milliseconds.
24
- */
25
- export type Duration = typeof Duration[keyof typeof Duration];
26
- //# sourceMappingURL=Duration.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Duration.d.ts","sourceRoot":"","sources":["../src/Client/Duration.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,QAAQ;IAEpB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC"}
package/lib/Duration.js DELETED
@@ -1,21 +0,0 @@
1
- /**
2
- * Provides some common durations in milliseconds.
3
- */
4
- export const Duration = Object.freeze({
5
- /**
6
- * One second.
7
- */
8
- Second: 1_000,
9
- /**
10
- * One minute.
11
- */
12
- Minute: 60_000,
13
- /**
14
- * One hour.
15
- */
16
- Hour: 3_600_000,
17
- /**
18
- * One day.
19
- */
20
- Day: 86_400_000
21
- });
@@ -1,30 +0,0 @@
1
- /**
2
- * Provides some common durations in milliseconds.
3
- */
4
- export const Duration = Object.freeze({
5
-
6
- /**
7
- * One second.
8
- */
9
- Second: 1_000,
10
-
11
- /**
12
- * One minute.
13
- */
14
- Minute: 60_000,
15
-
16
- /**
17
- * One hour.
18
- */
19
- Hour: 3_600_000,
20
-
21
- /**
22
- * One day.
23
- */
24
- Day: 86_400_000
25
- });
26
-
27
- /**
28
- * Provides some common durations in milliseconds.
29
- */
30
- export type Duration = typeof Duration[keyof typeof Duration];