@cedx/base 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.21.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.22.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).
@@ -1,10 +1,30 @@
1
1
  import { type Context } from "../Context.js";
2
- import { DialogResult } from "../DialogResult.js";
3
- import type { IDialogButton } from "./DialogButton.js";
2
+ import { Variant } from "../Variant.js";
3
+ /**
4
+ * Represents a dialog box button.
5
+ */
6
+ export interface IDialogButton {
7
+ /**
8
+ * The button icon.
9
+ */
10
+ icon?: string;
11
+ /**
12
+ * The button label.
13
+ */
14
+ label?: string;
15
+ /**
16
+ * The button value.
17
+ */
18
+ value?: string;
19
+ /**
20
+ * A tone variant.
21
+ */
22
+ variant?: Context | Variant;
23
+ }
4
24
  /**
5
25
  * Represents a message to display in a dialog box.
6
26
  */
7
- export interface IMessage {
27
+ export interface IDialogMessage {
8
28
  /**
9
29
  * The child content displayed in the body.
10
30
  */
@@ -64,6 +84,10 @@ export declare class DialogBox extends HTMLElement {
64
84
  */
65
85
  get open(): boolean;
66
86
  set open(value: boolean);
87
+ /**
88
+ * The dialog result.
89
+ */
90
+ get result(): string;
67
91
  /**
68
92
  * Value indicating whether the body is scrollable.
69
93
  */
@@ -77,26 +101,27 @@ export declare class DialogBox extends HTMLElement {
77
101
  */
78
102
  attributeChangedCallback(attribute: string, oldValue: string | null, newValue: string | null): void;
79
103
  /**
80
- * Shows an alert message with an "OK" button.
104
+ * Shows an alert message with an "OK" button by default.
81
105
  * @param context The contextual modifier.
82
106
  * @param caption The title displayed in the header.
83
- * @param body The child content displayed in the body.
84
- * @returns The dialog box result.
107
+ * @param message The child content displayed in the body.
108
+ * @param buttons The buttons displayed in the footer.
109
+ * @returns The dialog result.
85
110
  */
86
- alert(context: Context, caption: string, body: DocumentFragment): Promise<DialogResult>;
111
+ alert(context: Context, caption: string, message: DocumentFragment, buttons?: IDialogButton[]): Promise<string>;
87
112
  /**
88
113
  * Closes this dialog box.
89
- * @param result The dialog box result.
114
+ * @param result The dialog result.
90
115
  */
91
- close(result?: DialogResult): void;
116
+ close(result?: string): void;
92
117
  /**
93
118
  * Shows a confirmation message with two buttons, "OK" and "Cancel".
94
119
  * @param context The contextual modifier.
95
120
  * @param caption The title displayed in the header.
96
- * @param body The child content displayed in the body.
97
- * @returns The dialog box result.
121
+ * @param message The child content displayed in the body.
122
+ * @returns The dialog result.
98
123
  */
99
- confirm(context: Context, caption: string, body: DocumentFragment): Promise<DialogResult>;
124
+ confirm(context: Context, caption: string, message: DocumentFragment): Promise<string>;
100
125
  /**
101
126
  * Method invoked when this component is connected.
102
127
  */
@@ -108,18 +133,9 @@ export declare class DialogBox extends HTMLElement {
108
133
  /**
109
134
  * Shows a message.
110
135
  * @param message The message to show.
111
- * @returns The dialog box result.
112
- */
113
- show(message?: IMessage): Promise<DialogResult>;
114
- /**
115
- * Shows a message.
116
- * @param context The contextual modifier.
117
- * @param caption The title displayed in the header.
118
- * @param body The child content displayed in the body.
119
- * @param buttons The buttons displayed in the footer.
120
- * @returns The dialog box result.
136
+ * @returns The dialog result.
121
137
  */
122
- show(context: Context, caption: string, body: DocumentFragment, buttons?: IDialogButton[]): Promise<DialogResult>;
138
+ show(message?: IDialogMessage | null): Promise<string>;
123
139
  }
124
140
  /**
125
141
  * Declaration merging.
@@ -1 +1 @@
1
- {"version":3,"file":"DialogBox.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/DialogBox.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,OAAO,EAAiB,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAGhD,OAAO,KAAK,EAAe,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,QAAQ;IAExB;;OAEG;IACH,IAAI,EAAE,gBAAgB,CAAC;IAEvB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,WAAW;;IAEzC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAA0D;IAsB5F;;OAEG;;IAeH;;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,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAIjC;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,OAAO,CAEnB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,OAAO,EAE5B;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAW/F;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAMvF;;;OAGG;IACH,KAAK,CAAC,MAAM,GAAE,YAAgC,GAAG,IAAI;IAKrD;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAOzF;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAKzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAI5B;;;;OAIG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC;IAE/C;;;;;;;OAOG;IACH,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CAkHjH;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,YAAY,EAAE,SAAS,CAAC;KACxB;CACD"}
1
+ {"version":3,"file":"DialogBox.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/DialogBox.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,OAAO,EAA+B,MAAM,eAAe,CAAC;AAGzE,OAAO,EAAC,OAAO,EAAsB,MAAM,eAAe,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,aAAa;IAE7B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,GAAC,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAE9B;;OAEG;IACH,IAAI,EAAE,gBAAgB,CAAC;IAEvB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,WAAW;;IAEzC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,kBAAkB,WAA0D;IAiB5F;;OAEG;;IAeH;;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,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAIjC;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,OAAO,CAEnB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,OAAO,EAE5B;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAC,IAAI,GAAG,IAAI;IAW/F;;;;;;;OAOG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,GAAE,aAAa,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBnH;;;OAGG;IACH,KAAK,CAAC,MAAM,GAAE,MAA0B,GAAG,IAAI;IAK/C;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAOtF;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAKzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAI5B;;;;OAIG;IACH,IAAI,CAAC,OAAO,GAAE,cAAc,GAAC,IAAW,GAAG,OAAO,CAAC,MAAM,CAAC;CAgE1D;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,YAAY,EAAE,SAAS,CAAC;KACxB;CACD"}
@@ -1,8 +1,8 @@
1
1
  import { Modal } from "bootstrap";
2
- import { getIcon, toCss } from "../Context.js";
2
+ import { toCss as contextCss, getIcon } from "../Context.js";
3
3
  import { DialogResult } from "../DialogResult.js";
4
4
  import { html } from "../Tag.js";
5
- import { Variant } from "../Variant.js";
5
+ import { Variant, toCss as variantCss } from "../Variant.js";
6
6
  /**
7
7
  * Displays a dialog box, which presents a message to the user.
8
8
  */
@@ -11,20 +11,16 @@ export class DialogBox extends HTMLElement {
11
11
  * The list of observed attributes.
12
12
  */
13
13
  static observedAttributes = ["caption", "centered", "fade", "modal", "scrollable"];
14
- /**
15
- * The template for a button.
16
- */
17
- #buttonTemplate = this.querySelector("template").content;
18
14
  /**
19
15
  * The underlying Bootstrap modal.
20
16
  */
21
17
  #modal;
22
18
  /**
23
- * The function invoked to return the dialog box result.
19
+ * The function invoked to resolve the dialog result.
24
20
  */
25
- #resolve = () => { };
21
+ #resolve;
26
22
  /**
27
- * The dialog result.
23
+ * The promise providing the dialog result.
28
24
  */
29
25
  #result = DialogResult.None;
30
26
  /**
@@ -33,9 +29,9 @@ export class DialogBox extends HTMLElement {
33
29
  constructor() {
34
30
  super();
35
31
  this.firstElementChild.addEventListener("hidden.bs.modal", () => this.#resolve(this.#result));
36
- this.querySelector(".btn-close").addEventListener("click", this.#close);
32
+ this.querySelector(".btn-close").addEventListener("click", event => this.#close(event));
37
33
  for (const button of this.querySelectorAll(".modal-footer button"))
38
- button.addEventListener("click", this.#close);
34
+ button.addEventListener("click", event => this.#close(event));
39
35
  }
40
36
  /**
41
37
  * Registers the component.
@@ -47,7 +43,7 @@ export class DialogBox extends HTMLElement {
47
43
  * The child content displayed in the body.
48
44
  */
49
45
  set body(value) {
50
- this.querySelector(".modal-body > div").replaceChildren(...value.childNodes);
46
+ this.querySelector(".modal-body").replaceChildren(...value.childNodes);
51
47
  }
52
48
  /**
53
49
  * The title displayed in the header.
@@ -102,6 +98,12 @@ export class DialogBox extends HTMLElement {
102
98
  set open(value) {
103
99
  this.toggleAttribute("open", value);
104
100
  }
101
+ /**
102
+ * The dialog result.
103
+ */
104
+ get result() {
105
+ return this.#result;
106
+ }
105
107
  /**
106
108
  * Value indicating whether the body is scrollable.
107
109
  */
@@ -139,20 +141,35 @@ export class DialogBox extends HTMLElement {
139
141
  }
140
142
  }
141
143
  /**
142
- * Shows an alert message with an "OK" button.
144
+ * Shows an alert message with an "OK" button by default.
143
145
  * @param context The contextual modifier.
144
146
  * @param caption The title displayed in the header.
145
- * @param body The child content displayed in the body.
146
- * @returns The dialog box result.
147
+ * @param message The child content displayed in the body.
148
+ * @param buttons The buttons displayed in the footer.
149
+ * @returns The dialog result.
147
150
  */
148
- alert(context, caption, body) {
149
- return this.show(context, caption, this.#getBodyTemplate(context, body), [
150
- { label: "OK", value: DialogResult.OK, variant: Variant.Primary }
151
- ]);
151
+ alert(context, caption, message, buttons = []) {
152
+ return this.show({
153
+ caption,
154
+ body: html `
155
+ <div class="d-flex gap-2">
156
+ <i class="icon icon-fill fs-1 text-${contextCss(context)}"> ${getIcon(context)}</i>
157
+ <div class="flex-grow-1">${message}</div>
158
+ </div>
159
+ `,
160
+ footer: html `
161
+ ${(buttons.length ? buttons : [{ label: "OK", value: DialogResult.OK, variant: Variant.Primary }]).map(button => html `
162
+ <button class="btn btn-${variantCss(button.variant ?? Variant.Primary)}" type="button" value="${button.value ?? DialogResult.None}">
163
+ ${button.icon ? html `<i class="icon ${button.label ? "me-1" : ""}">${button.icon}</i>` : ""}
164
+ ${button.label}
165
+ </button>
166
+ `)}
167
+ `
168
+ });
152
169
  }
153
170
  /**
154
171
  * Closes this dialog box.
155
- * @param result The dialog box result.
172
+ * @param result The dialog result.
156
173
  */
157
174
  close(result = DialogResult.None) {
158
175
  this.#result = result;
@@ -162,11 +179,11 @@ export class DialogBox extends HTMLElement {
162
179
  * Shows a confirmation message with two buttons, "OK" and "Cancel".
163
180
  * @param context The contextual modifier.
164
181
  * @param caption The title displayed in the header.
165
- * @param body The child content displayed in the body.
166
- * @returns The dialog box result.
182
+ * @param message The child content displayed in the body.
183
+ * @returns The dialog result.
167
184
  */
168
- confirm(context, caption, body) {
169
- return this.show(context, caption, this.#getBodyTemplate(context, body), [
185
+ confirm(context, caption, message) {
186
+ return this.alert(context, caption, message, [
170
187
  { label: "OK", value: DialogResult.OK, variant: Variant.Primary },
171
188
  { label: "Annuler", value: DialogResult.Cancel, variant: Variant.Secondary }
172
189
  ]);
@@ -187,22 +204,14 @@ export class DialogBox extends HTMLElement {
187
204
  }
188
205
  /**
189
206
  * Shows a message.
190
- * @param message The message to show, or the contextual modifier.
191
- * @param caption The title displayed in the header.
192
- * @param body The child content displayed in the body.
193
- * @param buttons The buttons displayed in the footer.
194
- * @returns The dialog box result.
207
+ * @param message The message to show.
208
+ * @returns The dialog result.
195
209
  */
196
- show(message = null, caption = "", body = document.createDocumentFragment(), buttons = []) {
197
- if (typeof message == "string") {
198
- const footer = document.createDocumentFragment();
199
- footer.append(...buttons.map(button => this.#createButton(button)));
200
- message = { body, caption, footer };
201
- }
210
+ show(message = null) {
202
211
  if (message) {
203
212
  const footer = message.footer ?? document.createDocumentFragment();
204
213
  for (const button of footer.querySelectorAll("button"))
205
- button.addEventListener("click", this.#close);
214
+ button.addEventListener("click", event => this.#close(event));
206
215
  this.body = message.body;
207
216
  this.caption = message.caption;
208
217
  this.footer = footer;
@@ -217,40 +226,9 @@ export class DialogBox extends HTMLElement {
217
226
  * Closes this dialog box.
218
227
  * @param event The dispatched event.
219
228
  */
220
- #close = event => {
221
- const button = event.target.closest("button");
222
- this.close(Object.values(DialogResult).includes(button.value) ? button.value : DialogResult.None);
223
- };
224
- /**
225
- * Creates the component instance corresponding to the specified button.
226
- * @param button An object describing the appearance of the button.
227
- * @returns The component instance corresponding to the specified button.
228
- */
229
- #createButton(button) {
230
- const element = document.createElement("dialog-button");
231
- const childContent = this.#buttonTemplate.cloneNode(true).querySelector("button");
232
- childContent.addEventListener("click", this.#close);
233
- element.appendChild(childContent);
234
- element.context = button.context ?? null;
235
- element.icon = button.icon ?? null;
236
- element.label = button.label ?? "";
237
- element.value = button.value ?? DialogResult.None;
238
- element.variant = button.variant ?? null;
239
- return element;
240
- }
241
- /**
242
- * Gets the body template corresponding to the specified context and message.
243
- * @param context The contextual modifier.
244
- * @param message The child content displayed in the body.
245
- * @returns The body template corresponding to the specified context and message.
246
- */
247
- #getBodyTemplate(context, message) {
248
- return html `
249
- <div class="d-flex gap-2">
250
- <i class="icon icon-fill fs-1 text-${toCss(context)}"> ${getIcon(context)}</i>
251
- <div class="flex-grow-1">${message}</div>
252
- </div>
253
- `;
229
+ #close(event) {
230
+ event.preventDefault();
231
+ this.close(event.target.closest("button").value);
254
232
  }
255
233
  /**
256
234
  * Updates the title displayed in the header.
@@ -23,7 +23,7 @@ export class ThemeDropdown extends HTMLElement {
23
23
  constructor() {
24
24
  super();
25
25
  for (const button of this.querySelectorAll(".dropdown-menu button"))
26
- button.addEventListener("click", this.#setAppTheme);
26
+ button.addEventListener("click", event => this.#setAppTheme(event));
27
27
  }
28
28
  /**
29
29
  * Registers the component.
@@ -139,11 +139,11 @@ export class ThemeDropdown extends HTMLElement {
139
139
  * Changes the current application theme.
140
140
  * @param event The dispatched event.
141
141
  */
142
- #setAppTheme = event => {
142
+ #setAppTheme(event) {
143
143
  event.preventDefault();
144
144
  this.appTheme = event.target.closest("button").dataset.theme;
145
145
  this.save();
146
- };
146
+ }
147
147
  /**
148
148
  * Updates the alignment of the dropdown menu.
149
149
  * @param value The new value.
@@ -1,41 +1,4 @@
1
1
  import { Context } from "../Context.js";
2
- /**
3
- * Represents a notification.
4
- */
5
- export interface IToast {
6
- /**
7
- * Value indicating whether to automatically hide the toast.
8
- */
9
- autoHide?: boolean;
10
- /**
11
- * The child content displayed in the body.
12
- */
13
- body: DocumentFragment;
14
- /**
15
- * The title displayed in the header.
16
- */
17
- caption: string;
18
- /**
19
- * The default contextual modifier.
20
- */
21
- context?: Context;
22
- /**
23
- * The culture used to format the relative time.
24
- */
25
- culture?: Intl.Locale;
26
- /**
27
- * The delay, in milliseconds, to hide the toast.
28
- */
29
- delay?: number;
30
- /**
31
- * Value indicating whether to apply a transition.
32
- */
33
- fade?: boolean;
34
- /**
35
- * The icon displayed next to the caption.
36
- */
37
- icon?: string | null;
38
- }
39
2
  /**
40
3
  * Represents a notification.
41
4
  */
@@ -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,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,GAAC,IAAI,CAAC;CACnB;AAED;;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;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"}
@@ -170,7 +170,7 @@ export class Toast extends HTMLElement {
170
170
  connectedCallback() {
171
171
  const toast = this.firstElementChild;
172
172
  toast.addEventListener("hidden.bs.toast", () => clearInterval(this.#timer));
173
- toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(this.#updateElapsedTime, 1_000));
173
+ toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000));
174
174
  this.#toast = new BootstrapToast(toast);
175
175
  if (this.open)
176
176
  this.show();
@@ -243,10 +243,10 @@ export class Toast extends HTMLElement {
243
243
  /**
244
244
  * Updates the label corresponding to the elapsed time.
245
245
  */
246
- #updateElapsedTime = () => {
246
+ #updateElapsedTime() {
247
247
  const { elapsedTime } = this;
248
248
  this.querySelector(".toast-header small").textContent = elapsedTime > 0 ? this.#formatTime(elapsedTime / 1_000) : "";
249
- };
249
+ }
250
250
  /**
251
251
  * Updates the value indicating whether to apply a transition.
252
252
  * @param value The new value.
@@ -1,6 +1,42 @@
1
1
  import { Context } from "../Context.js";
2
2
  import { Position } from "../Position.js";
3
- import type { IToast } from "./Toast.js";
3
+ /**
4
+ * Represents a notification.
5
+ */
6
+ export interface IToast {
7
+ /**
8
+ * Value indicating whether to automatically hide the toast.
9
+ */
10
+ autoHide?: boolean;
11
+ /**
12
+ * The child content displayed in the body.
13
+ */
14
+ body: DocumentFragment;
15
+ /**
16
+ * The title displayed in the header.
17
+ */
18
+ caption: string;
19
+ /**
20
+ * The default contextual modifier.
21
+ */
22
+ context?: Context;
23
+ /**
24
+ * The culture used to format the relative time.
25
+ */
26
+ culture?: Intl.Locale;
27
+ /**
28
+ * The delay, in milliseconds, to hide the toast.
29
+ */
30
+ delay?: number;
31
+ /**
32
+ * Value indicating whether to apply a transition.
33
+ */
34
+ fade?: boolean;
35
+ /**
36
+ * The icon displayed next to the caption.
37
+ */
38
+ icon?: string;
39
+ }
4
40
  /**
5
41
  * Manages the notifications.
6
42
  */
@@ -60,9 +96,9 @@ export declare class Toaster extends HTMLElement {
60
96
  * Shows a toast.
61
97
  * @param context The contextual modifier.
62
98
  * @param caption The title displayed in the toast header.
63
- * @param body The child content displayed in the toast body.
99
+ * @param message The child content displayed in the toast body.
64
100
  */
65
- show(context: Context, caption: string, body: DocumentFragment): void;
101
+ notify(context: Context, caption: string, message: DocumentFragment): void;
66
102
  /**
67
103
  * Shows a toast.
68
104
  * @param toast The toast to show.
@@ -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;AAC/C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,YAAY,CAAC;AAEvC;;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,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAErE;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAsCzB;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;;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"}
@@ -114,13 +114,18 @@ export class Toaster extends HTMLElement {
114
114
  }
115
115
  /**
116
116
  * Shows a toast.
117
- * @param toast The toast to show, or the contextual modifier.
117
+ * @param context The contextual modifier.
118
118
  * @param caption The title displayed in the toast header.
119
- * @param body The child content displayed in the toast body.
119
+ * @param message The child content displayed in the toast body.
120
120
  */
121
- show(toast, caption = "", body = document.createDocumentFragment()) {
122
- if (typeof toast == "string")
123
- toast = { context: toast, caption, body };
121
+ notify(context, caption, message) {
122
+ return this.show({ body: message, caption, context });
123
+ }
124
+ /**
125
+ * Shows a toast.
126
+ * @param toast The toast to show.
127
+ */
128
+ show(toast) {
124
129
  const item = document.createElement("toaster-item");
125
130
  const childContent = this.#toastTemplate.cloneNode(true).querySelector(".toast");
126
131
  childContent.addEventListener("hidden.bs.toast", () => item.remove());
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Specifies the return value of a dialog box.
2
+ * Specifies common return values of a dialog box.
3
3
  */
4
4
  export declare const DialogResult: Readonly<{
5
5
  /**
6
6
  * The dialog box does not return any value.
7
7
  */
8
- None: "None";
8
+ None: "";
9
9
  /**
10
10
  * The return value of the dialog box is "OK".
11
11
  */
@@ -26,14 +26,6 @@ export declare const DialogResult: Readonly<{
26
26
  * The return value of the dialog box is "Ignore".
27
27
  */
28
28
  Ignore: "Ignore";
29
- /**
30
- * The return value of the dialog box is "Yes".
31
- */
32
- Yes: "Yes";
33
- /**
34
- * The return value of the dialog box is "No".
35
- */
36
- No: "No";
37
29
  }>;
38
30
  /**
39
31
  * Specifies the return value of a dialog box.
@@ -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;;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;AAEH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC"}
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Specifies the return value of a dialog box.
2
+ * Specifies common return values of a dialog box.
3
3
  */
4
4
  export const DialogResult = Object.freeze({
5
5
  /**
6
6
  * The dialog box does not return any value.
7
7
  */
8
- None: "None",
8
+ None: "",
9
9
  /**
10
10
  * The return value of the dialog box is "OK".
11
11
  */
@@ -25,13 +25,5 @@ export const DialogResult = Object.freeze({
25
25
  /**
26
26
  * The return value of the dialog box is "Ignore".
27
27
  */
28
- Ignore: "Ignore",
29
- /**
30
- * The return value of the dialog box is "Yes".
31
- */
32
- Yes: "Yes",
33
- /**
34
- * The return value of the dialog box is "No".
35
- */
36
- No: "No"
28
+ Ignore: "Ignore"
37
29
  });
package/lib/UI/Tag.js CHANGED
@@ -24,9 +24,11 @@ export function html(fragments, ...values) {
24
24
  * @returns The CSS string corresponding to the specified value.
25
25
  */
26
26
  function stringFromCss(value) {
27
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
28
- if (!(value instanceof CSSStyleSheet))
29
- return value === null || typeof value == "undefined" ? "" : String(value);
27
+ if (!(value instanceof CSSStyleSheet)) {
28
+ if (Array.isArray(value))
29
+ return value.map(stringFromCss).join("\n");
30
+ return value === null || typeof value == "undefined" ? "" : String(value); // eslint-disable-line @typescript-eslint/no-base-to-string
31
+ }
30
32
  return Array.from(value.cssRules).map(cssRule => cssRule.cssText).join("\n");
31
33
  }
32
34
  /**
@@ -35,9 +37,11 @@ function stringFromCss(value) {
35
37
  * @returns The HTML string corresponding to the specified value.
36
38
  */
37
39
  function stringFromHtml(value) {
38
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
39
- if (!(value instanceof DocumentFragment))
40
- return value === null || typeof value == "undefined" ? "" : String(value);
40
+ if (!(value instanceof DocumentFragment)) {
41
+ if (Array.isArray(value))
42
+ return value.map(stringFromHtml).join("");
43
+ return value === null || typeof value == "undefined" ? "" : String(value); // eslint-disable-line @typescript-eslint/no-base-to-string
44
+ }
41
45
  const element = document.createElement("div");
42
46
  element.appendChild(value);
43
47
  return element.innerHTML;
@@ -3,21 +3,25 @@
3
3
  */
4
4
  export declare const Variant: Readonly<{
5
5
  /**
6
- * A dark variant.
6
+ * A primary tone.
7
7
  */
8
- Dark: "Dark";
8
+ Primary: "Primary";
9
9
  /**
10
- * A light variant.
10
+ * A secondary tone.
11
11
  */
12
- Light: "Light";
12
+ Secondary: "Secondary";
13
13
  /**
14
- * A primary variant.
14
+ * A light tone.
15
15
  */
16
- Primary: "Primary";
16
+ Light: "Light";
17
17
  /**
18
- * A secondary variant.
18
+ * A dark tone.
19
19
  */
20
- Secondary: "Secondary";
20
+ Dark: "Dark";
21
+ Danger: "Danger";
22
+ Warning: "Warning";
23
+ Info: "Info";
24
+ Success: "Success";
21
25
  }>;
22
26
  /**
23
27
  * Defines tone variants.
@@ -1 +1 @@
1
- {"version":3,"file":"Variant.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Variant.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,OAAO;IAEnB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAE9C"}
1
+ {"version":3,"file":"Variant.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Variant.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,OAAO;IAGnB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;;;;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAE9C"}