@muxima-ui/core 1.0.0 → 1.2.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 (55) hide show
  1. package/README.md +12 -4
  2. package/fesm2022/muxima-ui-core-carousel.mjs +377 -0
  3. package/fesm2022/muxima-ui-core-carousel.mjs.map +1 -0
  4. package/fesm2022/muxima-ui-core-chips.mjs +349 -0
  5. package/fesm2022/muxima-ui-core-chips.mjs.map +1 -0
  6. package/fesm2022/muxima-ui-core-clipboard.mjs +110 -0
  7. package/fesm2022/muxima-ui-core-clipboard.mjs.map +1 -0
  8. package/fesm2022/muxima-ui-core-color-picker.mjs +755 -0
  9. package/fesm2022/muxima-ui-core-color-picker.mjs.map +1 -0
  10. package/fesm2022/muxima-ui-core-date-picker.mjs +494 -12
  11. package/fesm2022/muxima-ui-core-date-picker.mjs.map +1 -1
  12. package/fesm2022/muxima-ui-core-file-upload.mjs +392 -0
  13. package/fesm2022/muxima-ui-core-file-upload.mjs.map +1 -0
  14. package/fesm2022/muxima-ui-core-notification-center.mjs +487 -0
  15. package/fesm2022/muxima-ui-core-notification-center.mjs.map +1 -0
  16. package/fesm2022/muxima-ui-core-rating.mjs +212 -0
  17. package/fesm2022/muxima-ui-core-rating.mjs.map +1 -0
  18. package/fesm2022/muxima-ui-core-sidebar.mjs +333 -0
  19. package/fesm2022/muxima-ui-core-sidebar.mjs.map +1 -0
  20. package/fesm2022/muxima-ui-core-slider.mjs +211 -3
  21. package/fesm2022/muxima-ui-core-slider.mjs.map +1 -1
  22. package/fesm2022/muxima-ui-core-time-picker.mjs +389 -0
  23. package/fesm2022/muxima-ui-core-time-picker.mjs.map +1 -0
  24. package/fesm2022/muxima-ui-core-timeline.mjs +117 -0
  25. package/fesm2022/muxima-ui-core-timeline.mjs.map +1 -0
  26. package/fesm2022/muxima-ui-core.mjs +1 -1
  27. package/fesm2022/muxima-ui-core.mjs.map +1 -1
  28. package/package.json +41 -1
  29. package/styles/base.css +21 -1
  30. package/styles/components/carousel.css +113 -0
  31. package/styles/components/chips.css +170 -0
  32. package/styles/components/clipboard.css +52 -0
  33. package/styles/components/color-picker.css +207 -0
  34. package/styles/components/date-picker.css +135 -0
  35. package/styles/components/file-upload.css +164 -0
  36. package/styles/components/notification-center.css +220 -0
  37. package/styles/components/rating.css +89 -0
  38. package/styles/components/sidebar.css +211 -0
  39. package/styles/components/slider.css +111 -0
  40. package/styles/components/time-picker.css +39 -0
  41. package/styles/components/timeline.css +180 -0
  42. package/styles/muxima.css +10 -0
  43. package/types/muxima-ui-core-carousel.d.ts +72 -0
  44. package/types/muxima-ui-core-chips.d.ts +120 -0
  45. package/types/muxima-ui-core-clipboard.d.ts +42 -0
  46. package/types/muxima-ui-core-color-picker.d.ts +153 -0
  47. package/types/muxima-ui-core-date-picker.d.ts +130 -2
  48. package/types/muxima-ui-core-file-upload.d.ts +96 -0
  49. package/types/muxima-ui-core-notification-center.d.ts +91 -0
  50. package/types/muxima-ui-core-rating.d.ts +64 -0
  51. package/types/muxima-ui-core-sidebar.d.ts +115 -0
  52. package/types/muxima-ui-core-slider.d.ts +68 -6
  53. package/types/muxima-ui-core-time-picker.d.ts +83 -0
  54. package/types/muxima-ui-core-timeline.d.ts +59 -0
  55. package/types/muxima-ui-core.d.ts +1 -1
@@ -0,0 +1,487 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, TemplateRef, Directive, input, booleanAttribute, output, contentChild, signal, computed, DestroyRef, effect, untracked, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { NgTemplateOutlet } from '@angular/common';
4
+ import { LiveAnnouncer } from '@angular/cdk/a11y';
5
+ import { mxUniqueId } from '@muxima-ui/core/form-field';
6
+
7
+ /** "agora", "há 5 min", "ontem", "há 3 dias" e, depois de uma semana, a data. */
8
+ function mxRelativeTime(date, now = new Date(), locale = 'pt-AO') {
9
+ const diff = (date.getTime() - now.getTime()) / 1000;
10
+ const abs = Math.abs(diff);
11
+ if (abs < 45)
12
+ return 'agora';
13
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
14
+ if (abs < 3600)
15
+ return rtf.format(Math.round(diff / 60), 'minute');
16
+ if (abs < 86400)
17
+ return rtf.format(Math.round(diff / 3600), 'hour');
18
+ if (abs < 7 * 86400)
19
+ return rtf.format(Math.round(diff / 86400), 'day');
20
+ return new Intl.DateTimeFormat(locale, { day: 'numeric', month: 'short' }).format(date);
21
+ }
22
+ /** Modelo para o conteúdo de cada notificação: `<ng-template mxNotificationContent let-n>`. */
23
+ class MxNotificationContent {
24
+ template = inject(TemplateRef);
25
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxNotificationContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
26
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxNotificationContent, isStandalone: true, selector: "ng-template[mxNotificationContent]", ngImport: i0 });
27
+ }
28
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxNotificationContent, decorators: [{
29
+ type: Directive,
30
+ args: [{ selector: 'ng-template[mxNotificationContent]' }]
31
+ }] });
32
+ /**
33
+ * Lista de notificações com por ler e lidas, filtro "Por ler", "Marcar todas como lidas"
34
+ * e acções por notificação. Usa-se dentro de um popover, de um drawer ou numa página.
35
+ *
36
+ * ```html
37
+ * <mx-notification-center [items]="notificacoes()" (opened)="abrir($event)"
38
+ * (markRead)="marcar($event)" (markAllRead)="marcarTodas()" (dismiss)="remover($event)" />
39
+ * ```
40
+ *
41
+ * O componente não guarda estado: recebe a lista e emite o que a pessoa fez.
42
+ * Quando chegam notificações novas por ler, anuncia-as ao leitor de ecrã.
43
+ */
44
+ class MxNotificationCenter {
45
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
46
+ title = input('Notificações', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
47
+ /** Nível do título para o leitor de ecrã (h2 por omissão). */
48
+ headingLevel = input(2, ...(ngDevMode ? [{ debugName: "headingLevel" }] : /* istanbul ignore next */ []));
49
+ markAllText = input('Marcar todas como lidas', ...(ngDevMode ? [{ debugName: "markAllText" }] : /* istanbul ignore next */ []));
50
+ emptyText = input('Sem notificações.', ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
51
+ emptyUnreadText = input('Está tudo lido.', ...(ngDevMode ? [{ debugName: "emptyUnreadText" }] : /* istanbul ignore next */ []));
52
+ filterLabel = input('Mostrar', ...(ngDevMode ? [{ debugName: "filterLabel" }] : /* istanbul ignore next */ []));
53
+ /** Mostra os filtros Todas, Por ler e as categorias. */
54
+ showFilter = input(true, { ...(ngDevMode ? { debugName: "showFilter" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
55
+ /** Mostra o botão de remover em cada notificação. */
56
+ dismissible = input(false, { ...(ngDevMode ? { debugName: "dismissible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
57
+ /** Marca como lida ao abrir (emite markRead além de opened). */
58
+ markReadOnOpen = input(true, { ...(ngDevMode ? { debugName: "markReadOnOpen" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
59
+ /** Anuncia ao leitor de ecrã quando chegam notificações por ler. */
60
+ announce = input(true, { ...(ngDevMode ? { debugName: "announce" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
61
+ locale = input('pt-AO', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
62
+ opened = output();
63
+ markRead = output();
64
+ markAllRead = output();
65
+ dismiss = output();
66
+ contentTpl = contentChild(MxNotificationContent, ...(ngDevMode ? [{ debugName: "contentTpl" }] : /* istanbul ignore next */ []));
67
+ announcer = inject(LiveAnnouncer);
68
+ titleId = mxUniqueId('mx-notification-title');
69
+ filter = signal('all', ...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
70
+ /** Muda a cada minuto, para "há 5 min" se actualizar. */
71
+ now = signal(new Date(), ...(ngDevMode ? [{ debugName: "now" }] : /* istanbul ignore next */ []));
72
+ unread = computed(() => this.items().filter((n) => !n.read).length, ...(ngDevMode ? [{ debugName: "unread" }] : /* istanbul ignore next */ []));
73
+ categories = computed(() => [
74
+ ...new Set(this.items()
75
+ .map((n) => n.category)
76
+ .filter((c) => !!c)),
77
+ ], ...(ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []));
78
+ visible = computed(() => {
79
+ const f = this.filter();
80
+ const list = [...this.items()].sort((a, b) => b.time.getTime() - a.time.getTime());
81
+ if (f === 'unread')
82
+ return list.filter((n) => !n.read);
83
+ if (f !== 'all')
84
+ return list.filter((n) => n.category === f);
85
+ return list;
86
+ }, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
87
+ constructor() {
88
+ const timer = setInterval(() => this.now.set(new Date()), 60_000);
89
+ inject(DestroyRef).onDestroy(() => clearInterval(timer));
90
+ let previous = null;
91
+ effect(() => {
92
+ const items = this.items();
93
+ const ids = new Set(items.map((n) => n.id));
94
+ if (previous && untracked(() => this.announce())) {
95
+ const fresh = items.filter((n) => !n.read && !previous.has(n.id));
96
+ if (fresh.length)
97
+ this.announcer.announce(fresh.length === 1
98
+ ? `Nova notificação: ${fresh[0].title}`
99
+ : `${fresh.length} notificações novas`);
100
+ }
101
+ previous = ids;
102
+ });
103
+ }
104
+ relative(d) {
105
+ return mxRelativeTime(d, this.now(), this.locale());
106
+ }
107
+ open(n) {
108
+ if (!n.read && this.markReadOnOpen())
109
+ this.markRead.emit(n);
110
+ this.opened.emit(n);
111
+ }
112
+ dismissItem(n) {
113
+ this.dismiss.emit(n);
114
+ this.announcer.announce(`${n.title} removida.`);
115
+ }
116
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxNotificationCenter, deps: [], target: i0.ɵɵFactoryTarget.Component });
117
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: MxNotificationCenter, isStandalone: true, selector: "mx-notification-center", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null }, markAllText: { classPropertyName: "markAllText", publicName: "markAllText", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, emptyUnreadText: { classPropertyName: "emptyUnreadText", publicName: "emptyUnreadText", isSignal: true, isRequired: false, transformFunction: null }, filterLabel: { classPropertyName: "filterLabel", publicName: "filterLabel", isSignal: true, isRequired: false, transformFunction: null }, showFilter: { classPropertyName: "showFilter", publicName: "showFilter", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null }, markReadOnOpen: { classPropertyName: "markReadOnOpen", publicName: "markReadOnOpen", isSignal: true, isRequired: false, transformFunction: null }, announce: { classPropertyName: "announce", publicName: "announce", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", markRead: "markRead", markAllRead: "markAllRead", dismiss: "dismiss" }, host: { properties: { "attr.aria-label": "null" }, classAttribute: "mx-notification-center" }, queries: [{ propertyName: "contentTpl", first: true, predicate: MxNotificationContent, descendants: true, isSignal: true }], exportAs: ["mxNotificationCenter"], ngImport: i0, template: `
118
+ <div class="mx-notification-head">
119
+ <p
120
+ class="mx-notification-title"
121
+ role="heading"
122
+ [attr.aria-level]="headingLevel()"
123
+ [id]="titleId"
124
+ >
125
+ {{ title() }}
126
+ </p>
127
+ @if (unread()) {
128
+ <span class="mx-notification-count"
129
+ >{{ unread() }}<span class="mx-visually-hidden"> por ler</span></span
130
+ >
131
+ }
132
+ <button
133
+ type="button"
134
+ class="mx-notification-link"
135
+ [disabled]="!unread()"
136
+ (click)="markAllRead.emit()"
137
+ >
138
+ {{ markAllText() }}
139
+ </button>
140
+ </div>
141
+
142
+ @if (showFilter()) {
143
+ <div class="mx-notification-filters" role="group" [attr.aria-label]="filterLabel()">
144
+ <button
145
+ type="button"
146
+ class="mx-chip mx-chip-toggle"
147
+ data-size="sm"
148
+ [attr.aria-pressed]="filter() === 'all'"
149
+ (click)="filter.set('all')"
150
+ >
151
+ Todas
152
+ </button>
153
+ <button
154
+ type="button"
155
+ class="mx-chip mx-chip-toggle"
156
+ data-size="sm"
157
+ [attr.aria-pressed]="filter() === 'unread'"
158
+ (click)="filter.set('unread')"
159
+ >
160
+ Por ler ({{ unread() }})
161
+ </button>
162
+ @for (c of categories(); track c) {
163
+ <button
164
+ type="button"
165
+ class="mx-chip mx-chip-toggle"
166
+ data-size="sm"
167
+ [attr.aria-pressed]="filter() === c"
168
+ (click)="filter.set(c)"
169
+ >
170
+ {{ c }}
171
+ </button>
172
+ }
173
+ </div>
174
+ }
175
+
176
+ @if (visible().length) {
177
+ <ul class="mx-notification-list" [attr.aria-labelledby]="titleId">
178
+ @for (n of visible(); track n.id) {
179
+ <li
180
+ class="mx-notification"
181
+ [attr.data-unread]="n.read ? null : ''"
182
+ [attr.data-variant]="n.variant && n.variant !== 'default' ? n.variant : null"
183
+ >
184
+ <span class="mx-notification-dot" aria-hidden="true"></span>
185
+ <button type="button" class="mx-notification-main" (click)="open(n)">
186
+ @if (!n.read) {
187
+ <span class="mx-visually-hidden">Por ler: </span>
188
+ }
189
+ @if (contentTpl(); as tpl) {
190
+ <ng-container *ngTemplateOutlet="tpl.template; context: { $implicit: n }" />
191
+ } @else {
192
+ <span class="mx-notification-text">{{ n.title }}</span>
193
+ @if (n.description) {
194
+ <span class="mx-notification-desc">{{ n.description }}</span>
195
+ }
196
+ }
197
+ <time class="mx-notification-time" [attr.datetime]="n.time.toISOString()">{{
198
+ relative(n.time)
199
+ }}</time>
200
+ </button>
201
+ <div class="mx-notification-actions">
202
+ @if (!n.read) {
203
+ <button
204
+ type="button"
205
+ class="mx-notification-action"
206
+ [attr.aria-label]="'Marcar como lida: ' + n.title"
207
+ (click)="markRead.emit(n)"
208
+ >
209
+ <svg viewBox="0 0 16 16" aria-hidden="true">
210
+ <path
211
+ d="M3.5 8.5l3 3 6-7"
212
+ fill="none"
213
+ stroke="currentColor"
214
+ stroke-width="1.5"
215
+ stroke-linecap="round"
216
+ stroke-linejoin="round"
217
+ />
218
+ </svg>
219
+ </button>
220
+ }
221
+ @if (dismissible()) {
222
+ <button
223
+ type="button"
224
+ class="mx-notification-action"
225
+ [attr.aria-label]="'Remover: ' + n.title"
226
+ (click)="dismissItem(n)"
227
+ >
228
+ <svg viewBox="0 0 16 16" aria-hidden="true">
229
+ <path
230
+ d="M4.5 4.5l7 7M11.5 4.5l-7 7"
231
+ fill="none"
232
+ stroke="currentColor"
233
+ stroke-width="1.5"
234
+ stroke-linecap="round"
235
+ />
236
+ </svg>
237
+ </button>
238
+ }
239
+ </div>
240
+ </li>
241
+ }
242
+ </ul>
243
+ } @else {
244
+ <div class="mx-notification-empty">
245
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
246
+ <path
247
+ d="M6 16.5V11a6 6 0 1 1 12 0v5.5l1.5 2h-15l1.5-2z M10 20.5a2 2 0 0 0 4 0"
248
+ stroke="currentColor"
249
+ stroke-width="1.5"
250
+ stroke-linejoin="round"
251
+ />
252
+ </svg>
253
+ <p>{{ filter() === 'unread' ? emptyUnreadText() : emptyText() }}</p>
254
+ </div>
255
+ }
256
+ <ng-content select="[mxNotificationFooter]" />
257
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
258
+ }
259
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxNotificationCenter, decorators: [{
260
+ type: Component,
261
+ args: [{
262
+ selector: 'mx-notification-center',
263
+ exportAs: 'mxNotificationCenter',
264
+ imports: [NgTemplateOutlet],
265
+ changeDetection: ChangeDetectionStrategy.OnPush,
266
+ encapsulation: ViewEncapsulation.None,
267
+ host: { class: 'mx-notification-center', '[attr.aria-label]': 'null' },
268
+ template: `
269
+ <div class="mx-notification-head">
270
+ <p
271
+ class="mx-notification-title"
272
+ role="heading"
273
+ [attr.aria-level]="headingLevel()"
274
+ [id]="titleId"
275
+ >
276
+ {{ title() }}
277
+ </p>
278
+ @if (unread()) {
279
+ <span class="mx-notification-count"
280
+ >{{ unread() }}<span class="mx-visually-hidden"> por ler</span></span
281
+ >
282
+ }
283
+ <button
284
+ type="button"
285
+ class="mx-notification-link"
286
+ [disabled]="!unread()"
287
+ (click)="markAllRead.emit()"
288
+ >
289
+ {{ markAllText() }}
290
+ </button>
291
+ </div>
292
+
293
+ @if (showFilter()) {
294
+ <div class="mx-notification-filters" role="group" [attr.aria-label]="filterLabel()">
295
+ <button
296
+ type="button"
297
+ class="mx-chip mx-chip-toggle"
298
+ data-size="sm"
299
+ [attr.aria-pressed]="filter() === 'all'"
300
+ (click)="filter.set('all')"
301
+ >
302
+ Todas
303
+ </button>
304
+ <button
305
+ type="button"
306
+ class="mx-chip mx-chip-toggle"
307
+ data-size="sm"
308
+ [attr.aria-pressed]="filter() === 'unread'"
309
+ (click)="filter.set('unread')"
310
+ >
311
+ Por ler ({{ unread() }})
312
+ </button>
313
+ @for (c of categories(); track c) {
314
+ <button
315
+ type="button"
316
+ class="mx-chip mx-chip-toggle"
317
+ data-size="sm"
318
+ [attr.aria-pressed]="filter() === c"
319
+ (click)="filter.set(c)"
320
+ >
321
+ {{ c }}
322
+ </button>
323
+ }
324
+ </div>
325
+ }
326
+
327
+ @if (visible().length) {
328
+ <ul class="mx-notification-list" [attr.aria-labelledby]="titleId">
329
+ @for (n of visible(); track n.id) {
330
+ <li
331
+ class="mx-notification"
332
+ [attr.data-unread]="n.read ? null : ''"
333
+ [attr.data-variant]="n.variant && n.variant !== 'default' ? n.variant : null"
334
+ >
335
+ <span class="mx-notification-dot" aria-hidden="true"></span>
336
+ <button type="button" class="mx-notification-main" (click)="open(n)">
337
+ @if (!n.read) {
338
+ <span class="mx-visually-hidden">Por ler: </span>
339
+ }
340
+ @if (contentTpl(); as tpl) {
341
+ <ng-container *ngTemplateOutlet="tpl.template; context: { $implicit: n }" />
342
+ } @else {
343
+ <span class="mx-notification-text">{{ n.title }}</span>
344
+ @if (n.description) {
345
+ <span class="mx-notification-desc">{{ n.description }}</span>
346
+ }
347
+ }
348
+ <time class="mx-notification-time" [attr.datetime]="n.time.toISOString()">{{
349
+ relative(n.time)
350
+ }}</time>
351
+ </button>
352
+ <div class="mx-notification-actions">
353
+ @if (!n.read) {
354
+ <button
355
+ type="button"
356
+ class="mx-notification-action"
357
+ [attr.aria-label]="'Marcar como lida: ' + n.title"
358
+ (click)="markRead.emit(n)"
359
+ >
360
+ <svg viewBox="0 0 16 16" aria-hidden="true">
361
+ <path
362
+ d="M3.5 8.5l3 3 6-7"
363
+ fill="none"
364
+ stroke="currentColor"
365
+ stroke-width="1.5"
366
+ stroke-linecap="round"
367
+ stroke-linejoin="round"
368
+ />
369
+ </svg>
370
+ </button>
371
+ }
372
+ @if (dismissible()) {
373
+ <button
374
+ type="button"
375
+ class="mx-notification-action"
376
+ [attr.aria-label]="'Remover: ' + n.title"
377
+ (click)="dismissItem(n)"
378
+ >
379
+ <svg viewBox="0 0 16 16" aria-hidden="true">
380
+ <path
381
+ d="M4.5 4.5l7 7M11.5 4.5l-7 7"
382
+ fill="none"
383
+ stroke="currentColor"
384
+ stroke-width="1.5"
385
+ stroke-linecap="round"
386
+ />
387
+ </svg>
388
+ </button>
389
+ }
390
+ </div>
391
+ </li>
392
+ }
393
+ </ul>
394
+ } @else {
395
+ <div class="mx-notification-empty">
396
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
397
+ <path
398
+ d="M6 16.5V11a6 6 0 1 1 12 0v5.5l1.5 2h-15l1.5-2z M10 20.5a2 2 0 0 0 4 0"
399
+ stroke="currentColor"
400
+ stroke-width="1.5"
401
+ stroke-linejoin="round"
402
+ />
403
+ </svg>
404
+ <p>{{ filter() === 'unread' ? emptyUnreadText() : emptyText() }}</p>
405
+ </div>
406
+ }
407
+ <ng-content select="[mxNotificationFooter]" />
408
+ `,
409
+ }]
410
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], headingLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingLevel", required: false }] }], markAllText: [{ type: i0.Input, args: [{ isSignal: true, alias: "markAllText", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], emptyUnreadText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyUnreadText", required: false }] }], filterLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterLabel", required: false }] }], showFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilter", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], markReadOnOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "markReadOnOpen", required: false }] }], announce: [{ type: i0.Input, args: [{ isSignal: true, alias: "announce", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], markRead: [{ type: i0.Output, args: ["markRead"] }], markAllRead: [{ type: i0.Output, args: ["markAllRead"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }], contentTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => MxNotificationContent), { isSignal: true }] }] } });
411
+ /**
412
+ * Botão do sino com a contagem por ler. O nome inclui a contagem:
413
+ * "Notificações, 3 por ler".
414
+ *
415
+ * ```html
416
+ * <button mxNotificationBell [count]="porLer()" [mxPopoverTrigger]="painel"></button>
417
+ * ```
418
+ */
419
+ class MxNotificationBell {
420
+ count = input(0, ...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
421
+ max = input(99, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
422
+ label = input('Notificações', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
423
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxNotificationBell, deps: [], target: i0.ɵɵFactoryTarget.Component });
424
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: MxNotificationBell, isStandalone: true, selector: "button[mxNotificationBell]", inputs: { count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, properties: { "attr.aria-label": "count() ? label() + \", \" + count() + \" por ler\" : label()" }, classAttribute: "mx-notification-bell" }, exportAs: ["mxNotificationBell"], ngImport: i0, template: `
425
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
426
+ <path
427
+ d="M6 16.5V11a6 6 0 1 1 12 0v5.5l1.5 2h-15l1.5-2z"
428
+ stroke="currentColor"
429
+ stroke-width="1.75"
430
+ stroke-linejoin="round"
431
+ />
432
+ <path
433
+ d="M10 20.5a2 2 0 0 0 4 0"
434
+ stroke="currentColor"
435
+ stroke-width="1.75"
436
+ stroke-linecap="round"
437
+ />
438
+ </svg>
439
+ @if (count()) {
440
+ <span class="mx-notification-bell-count" aria-hidden="true">{{
441
+ count() > max() ? max() + '+' : count()
442
+ }}</span>
443
+ }
444
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
445
+ }
446
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxNotificationBell, decorators: [{
447
+ type: Component,
448
+ args: [{
449
+ selector: 'button[mxNotificationBell]',
450
+ exportAs: 'mxNotificationBell',
451
+ changeDetection: ChangeDetectionStrategy.OnPush,
452
+ encapsulation: ViewEncapsulation.None,
453
+ host: {
454
+ class: 'mx-notification-bell',
455
+ type: 'button',
456
+ '[attr.aria-label]': 'count() ? label() + ", " + count() + " por ler" : label()',
457
+ },
458
+ template: `
459
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
460
+ <path
461
+ d="M6 16.5V11a6 6 0 1 1 12 0v5.5l1.5 2h-15l1.5-2z"
462
+ stroke="currentColor"
463
+ stroke-width="1.75"
464
+ stroke-linejoin="round"
465
+ />
466
+ <path
467
+ d="M10 20.5a2 2 0 0 0 4 0"
468
+ stroke="currentColor"
469
+ stroke-width="1.75"
470
+ stroke-linecap="round"
471
+ />
472
+ </svg>
473
+ @if (count()) {
474
+ <span class="mx-notification-bell-count" aria-hidden="true">{{
475
+ count() > max() ? max() + '+' : count()
476
+ }}</span>
477
+ }
478
+ `,
479
+ }]
480
+ }], propDecorators: { count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
481
+
482
+ /**
483
+ * Generated bundle index. Do not edit.
484
+ */
485
+
486
+ export { MxNotificationBell, MxNotificationCenter, MxNotificationContent, mxRelativeTime };
487
+ //# sourceMappingURL=muxima-ui-core-notification-center.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxima-ui-core-notification-center.mjs","sources":["../../../projects/core/notification-center/notification-center.ts","../../../projects/core/notification-center/muxima-ui-core-notification-center.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n Directive,\n TemplateRef,\n ViewEncapsulation,\n booleanAttribute,\n computed,\n contentChild,\n effect,\n inject,\n input,\n output,\n signal,\n untracked,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { LiveAnnouncer } from '@angular/cdk/a11y';\nimport { mxUniqueId } from '@muxima-ui/core/form-field';\n\nexport interface MxNotification<D = unknown> {\n id: string | number;\n title: string;\n description?: string;\n time: Date;\n read?: boolean;\n /** Cor do marcador: info em Kwanza, success, warning, danger. */\n variant?: 'default' | 'info' | 'success' | 'warning' | 'danger';\n /** Agrupa por categoria nos filtros (ex.: \"Facturas\"). */\n category?: string;\n data?: D;\n}\n\n/** \"agora\", \"há 5 min\", \"ontem\", \"há 3 dias\" e, depois de uma semana, a data. */\nexport function mxRelativeTime(date: Date, now = new Date(), locale = 'pt-AO'): string {\n const diff = (date.getTime() - now.getTime()) / 1000;\n const abs = Math.abs(diff);\n if (abs < 45) return 'agora';\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });\n if (abs < 3600) return rtf.format(Math.round(diff / 60), 'minute');\n if (abs < 86400) return rtf.format(Math.round(diff / 3600), 'hour');\n if (abs < 7 * 86400) return rtf.format(Math.round(diff / 86400), 'day');\n return new Intl.DateTimeFormat(locale, { day: 'numeric', month: 'short' }).format(date);\n}\n\n/** Modelo para o conteúdo de cada notificação: `<ng-template mxNotificationContent let-n>`. */\n@Directive({ selector: 'ng-template[mxNotificationContent]' })\nexport class MxNotificationContent {\n readonly template = inject(TemplateRef);\n}\n\n/**\n * Lista de notificações com por ler e lidas, filtro \"Por ler\", \"Marcar todas como lidas\"\n * e acções por notificação. Usa-se dentro de um popover, de um drawer ou numa página.\n *\n * ```html\n * <mx-notification-center [items]=\"notificacoes()\" (opened)=\"abrir($event)\"\n * (markRead)=\"marcar($event)\" (markAllRead)=\"marcarTodas()\" (dismiss)=\"remover($event)\" />\n * ```\n *\n * O componente não guarda estado: recebe a lista e emite o que a pessoa fez.\n * Quando chegam notificações novas por ler, anuncia-as ao leitor de ecrã.\n */\n@Component({\n selector: 'mx-notification-center',\n exportAs: 'mxNotificationCenter',\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'mx-notification-center', '[attr.aria-label]': 'null' },\n template: `\n <div class=\"mx-notification-head\">\n <p\n class=\"mx-notification-title\"\n role=\"heading\"\n [attr.aria-level]=\"headingLevel()\"\n [id]=\"titleId\"\n >\n {{ title() }}\n </p>\n @if (unread()) {\n <span class=\"mx-notification-count\"\n >{{ unread() }}<span class=\"mx-visually-hidden\"> por ler</span></span\n >\n }\n <button\n type=\"button\"\n class=\"mx-notification-link\"\n [disabled]=\"!unread()\"\n (click)=\"markAllRead.emit()\"\n >\n {{ markAllText() }}\n </button>\n </div>\n\n @if (showFilter()) {\n <div class=\"mx-notification-filters\" role=\"group\" [attr.aria-label]=\"filterLabel()\">\n <button\n type=\"button\"\n class=\"mx-chip mx-chip-toggle\"\n data-size=\"sm\"\n [attr.aria-pressed]=\"filter() === 'all'\"\n (click)=\"filter.set('all')\"\n >\n Todas\n </button>\n <button\n type=\"button\"\n class=\"mx-chip mx-chip-toggle\"\n data-size=\"sm\"\n [attr.aria-pressed]=\"filter() === 'unread'\"\n (click)=\"filter.set('unread')\"\n >\n Por ler ({{ unread() }})\n </button>\n @for (c of categories(); track c) {\n <button\n type=\"button\"\n class=\"mx-chip mx-chip-toggle\"\n data-size=\"sm\"\n [attr.aria-pressed]=\"filter() === c\"\n (click)=\"filter.set(c)\"\n >\n {{ c }}\n </button>\n }\n </div>\n }\n\n @if (visible().length) {\n <ul class=\"mx-notification-list\" [attr.aria-labelledby]=\"titleId\">\n @for (n of visible(); track n.id) {\n <li\n class=\"mx-notification\"\n [attr.data-unread]=\"n.read ? null : ''\"\n [attr.data-variant]=\"n.variant && n.variant !== 'default' ? n.variant : null\"\n >\n <span class=\"mx-notification-dot\" aria-hidden=\"true\"></span>\n <button type=\"button\" class=\"mx-notification-main\" (click)=\"open(n)\">\n @if (!n.read) {\n <span class=\"mx-visually-hidden\">Por ler: </span>\n }\n @if (contentTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.template; context: { $implicit: n }\" />\n } @else {\n <span class=\"mx-notification-text\">{{ n.title }}</span>\n @if (n.description) {\n <span class=\"mx-notification-desc\">{{ n.description }}</span>\n }\n }\n <time class=\"mx-notification-time\" [attr.datetime]=\"n.time.toISOString()\">{{\n relative(n.time)\n }}</time>\n </button>\n <div class=\"mx-notification-actions\">\n @if (!n.read) {\n <button\n type=\"button\"\n class=\"mx-notification-action\"\n [attr.aria-label]=\"'Marcar como lida: ' + n.title\"\n (click)=\"markRead.emit(n)\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M3.5 8.5l3 3 6-7\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n @if (dismissible()) {\n <button\n type=\"button\"\n class=\"mx-notification-action\"\n [attr.aria-label]=\"'Remover: ' + n.title\"\n (click)=\"dismissItem(n)\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M4.5 4.5l7 7M11.5 4.5l-7 7\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n </li>\n }\n </ul>\n } @else {\n <div class=\"mx-notification-empty\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M6 16.5V11a6 6 0 1 1 12 0v5.5l1.5 2h-15l1.5-2z M10 20.5a2 2 0 0 0 4 0\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <p>{{ filter() === 'unread' ? emptyUnreadText() : emptyText() }}</p>\n </div>\n }\n <ng-content select=\"[mxNotificationFooter]\" />\n `,\n})\nexport class MxNotificationCenter<D = unknown> {\n readonly items = input.required<readonly MxNotification<D>[]>();\n readonly title = input('Notificações');\n /** Nível do título para o leitor de ecrã (h2 por omissão). */\n readonly headingLevel = input(2);\n readonly markAllText = input('Marcar todas como lidas');\n readonly emptyText = input('Sem notificações.');\n readonly emptyUnreadText = input('Está tudo lido.');\n readonly filterLabel = input('Mostrar');\n /** Mostra os filtros Todas, Por ler e as categorias. */\n readonly showFilter = input(true, { transform: booleanAttribute });\n /** Mostra o botão de remover em cada notificação. */\n readonly dismissible = input(false, { transform: booleanAttribute });\n /** Marca como lida ao abrir (emite markRead além de opened). */\n readonly markReadOnOpen = input(true, { transform: booleanAttribute });\n /** Anuncia ao leitor de ecrã quando chegam notificações por ler. */\n readonly announce = input(true, { transform: booleanAttribute });\n readonly locale = input('pt-AO');\n\n readonly opened = output<MxNotification<D>>();\n readonly markRead = output<MxNotification<D>>();\n readonly markAllRead = output<void>();\n readonly dismiss = output<MxNotification<D>>();\n\n protected readonly contentTpl = contentChild(MxNotificationContent);\n private readonly announcer = inject(LiveAnnouncer);\n protected readonly titleId = mxUniqueId('mx-notification-title');\n readonly filter = signal<string>('all');\n /** Muda a cada minuto, para \"há 5 min\" se actualizar. */\n private readonly now = signal(new Date());\n\n readonly unread = computed(() => this.items().filter((n) => !n.read).length);\n protected readonly categories = computed(() => [\n ...new Set(\n this.items()\n .map((n) => n.category)\n .filter((c): c is string => !!c),\n ),\n ]);\n protected readonly visible = computed(() => {\n const f = this.filter();\n const list = [...this.items()].sort((a, b) => b.time.getTime() - a.time.getTime());\n if (f === 'unread') return list.filter((n) => !n.read);\n if (f !== 'all') return list.filter((n) => n.category === f);\n return list;\n });\n\n constructor() {\n const timer = setInterval(() => this.now.set(new Date()), 60_000);\n inject(DestroyRef).onDestroy(() => clearInterval(timer));\n let previous: Set<string | number> | null = null;\n effect(() => {\n const items = this.items();\n const ids = new Set(items.map((n) => n.id));\n if (previous && untracked(() => this.announce())) {\n const fresh = items.filter((n) => !n.read && !previous!.has(n.id));\n if (fresh.length)\n this.announcer.announce(\n fresh.length === 1\n ? `Nova notificação: ${fresh[0].title}`\n : `${fresh.length} notificações novas`,\n );\n }\n previous = ids;\n });\n }\n\n protected relative(d: Date): string {\n return mxRelativeTime(d, this.now(), this.locale());\n }\n\n protected open(n: MxNotification<D>): void {\n if (!n.read && this.markReadOnOpen()) this.markRead.emit(n);\n this.opened.emit(n);\n }\n\n protected dismissItem(n: MxNotification<D>): void {\n this.dismiss.emit(n);\n this.announcer.announce(`${n.title} removida.`);\n }\n}\n\n/**\n * Botão do sino com a contagem por ler. O nome inclui a contagem:\n * \"Notificações, 3 por ler\".\n *\n * ```html\n * <button mxNotificationBell [count]=\"porLer()\" [mxPopoverTrigger]=\"painel\"></button>\n * ```\n */\n@Component({\n selector: 'button[mxNotificationBell]',\n exportAs: 'mxNotificationBell',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'mx-notification-bell',\n type: 'button',\n '[attr.aria-label]': 'count() ? label() + \", \" + count() + \" por ler\" : label()',\n },\n template: `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M6 16.5V11a6 6 0 1 1 12 0v5.5l1.5 2h-15l1.5-2z\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M10 20.5a2 2 0 0 0 4 0\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n />\n </svg>\n @if (count()) {\n <span class=\"mx-notification-bell-count\" aria-hidden=\"true\">{{\n count() > max() ? max() + '+' : count()\n }}</span>\n }\n `,\n})\nexport class MxNotificationBell {\n readonly count = input(0);\n readonly max = input(99);\n readonly label = input('Notificações');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAkCA;AACM,SAAU,cAAc,CAAC,IAAU,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,EAAE,MAAM,GAAG,OAAO,EAAA;AAC3E,IAAA,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,IAAI;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1B,IAAI,GAAG,GAAG,EAAE;AAAE,QAAA,OAAO,OAAO;AAC5B,IAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACpE,IAAI,GAAG,GAAG,IAAI;AAAE,QAAA,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC;IAClE,IAAI,GAAG,GAAG,KAAK;AAAE,QAAA,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,MAAM,CAAC;AACnE,IAAA,IAAI,GAAG,GAAG,CAAC,GAAG,KAAK;AAAE,QAAA,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE,KAAK,CAAC;IACvE,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACzF;AAEA;MAEa,qBAAqB,CAAA;AACvB,IAAA,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC;wGAD5B,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAArB,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oCAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;4FAArB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBADjC,SAAS;mBAAC,EAAE,QAAQ,EAAE,oCAAoC,EAAE;;AAK7D;;;;;;;;;;;AAWG;MAsJU,oBAAoB,CAAA;AACtB,IAAA,KAAK,GAAG,KAAK,CAAC,QAAQ,2EAAgC;AACtD,IAAA,KAAK,GAAG,KAAK,CAAC,cAAc,4EAAC;;AAE7B,IAAA,YAAY,GAAG,KAAK,CAAC,CAAC,mFAAC;AACvB,IAAA,WAAW,GAAG,KAAK,CAAC,yBAAyB,kFAAC;AAC9C,IAAA,SAAS,GAAG,KAAK,CAAC,mBAAmB,gFAAC;AACtC,IAAA,eAAe,GAAG,KAAK,CAAC,iBAAiB,sFAAC;AAC1C,IAAA,WAAW,GAAG,KAAK,CAAC,SAAS,kFAAC;;IAE9B,UAAU,GAAG,KAAK,CAAC,IAAI,kFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;IAEzD,WAAW,GAAG,KAAK,CAAC,KAAK,mFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;IAE3D,cAAc,GAAG,KAAK,CAAC,IAAI,sFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;IAE7D,QAAQ,GAAG,KAAK,CAAC,IAAI,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AACvD,IAAA,MAAM,GAAG,KAAK,CAAC,OAAO,6EAAC;IAEvB,MAAM,GAAG,MAAM,EAAqB;IACpC,QAAQ,GAAG,MAAM,EAAqB;IACtC,WAAW,GAAG,MAAM,EAAQ;IAC5B,OAAO,GAAG,MAAM,EAAqB;AAE3B,IAAA,UAAU,GAAG,YAAY,CAAC,qBAAqB,iFAAC;AAClD,IAAA,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC;AAC/B,IAAA,OAAO,GAAG,UAAU,CAAC,uBAAuB,CAAC;AACvD,IAAA,MAAM,GAAG,MAAM,CAAS,KAAK,6EAAC;;AAEtB,IAAA,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,0EAAC;IAEhC,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,QAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;AACzD,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAM;AAC7C,QAAA,GAAG,IAAI,GAAG,CACR,IAAI,CAAC,KAAK;aACP,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ;aACrB,MAAM,CAAC,CAAC,CAAC,KAAkB,CAAC,CAAC,CAAC,CAAC,CACnC;AACF,KAAA,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,YAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;AACiB,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE;AACvB,QAAA,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClF,IAAI,CAAC,KAAK,QAAQ;AAAE,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACtD,IAAI,CAAC,KAAK,KAAK;AAAE,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC;AAC5D,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,8EAAC;AAEF,IAAA,WAAA,GAAA;QACE,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC;AACjE,QAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;QACxD,IAAI,QAAQ,GAAgC,IAAI;QAChD,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE;AAC1B,YAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3C,YAAA,IAAI,QAAQ,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;gBAChD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAClE,IAAI,KAAK,CAAC,MAAM;oBACd,IAAI,CAAC,SAAS,CAAC,QAAQ,CACrB,KAAK,CAAC,MAAM,KAAK;0BACb,qBAAqB,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;AACrC,0BAAE,CAAA,EAAG,KAAK,CAAC,MAAM,CAAA,mBAAA,CAAqB,CACzC;YACL;YACA,QAAQ,GAAG,GAAG;AAChB,QAAA,CAAC,CAAC;IACJ;AAEU,IAAA,QAAQ,CAAC,CAAO,EAAA;AACxB,QAAA,OAAO,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IACrD;AAEU,IAAA,IAAI,CAAC,CAAoB,EAAA;QACjC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE;AAAE,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3D,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACrB;AAEU,IAAA,WAAW,CAAC,CAAoB,EAAA;AACxC,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA,EAAG,CAAC,CAAC,KAAK,CAAA,UAAA,CAAY,CAAC;IACjD;wGA/EW,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAApB,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,QAAA,EAAA,UAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,wBAAA,EAAA,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,YAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAwBc,qBAAqB,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,sBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAtKxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4IT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAhJS,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;4FAkJf,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBArJhC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,wBAAwB;AAClC,oBAAA,QAAQ,EAAE,sBAAsB;oBAChC,OAAO,EAAE,CAAC,gBAAgB,CAAC;oBAC3B,eAAe,EAAE,uBAAuB,CAAC,MAAM;oBAC/C,aAAa,EAAE,iBAAiB,CAAC,IAAI;oBACrC,IAAI,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,EAAE;AACtE,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4IT,EAAA,CAAA;AACF,iBAAA;s/CAyB8C,qBAAqB,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;AA0DpE;;;;;;;AAOG;MAiCU,kBAAkB,CAAA;AACpB,IAAA,KAAK,GAAG,KAAK,CAAC,CAAC,4EAAC;AAChB,IAAA,GAAG,GAAG,KAAK,CAAC,EAAE,0EAAC;AACf,IAAA,KAAK,GAAG,KAAK,CAAC,cAAc,4EAAC;wGAH3B,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,4BAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,GAAA,EAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,+DAAA,EAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,EAAA,QAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAtBnB;;;;;;;;;;;;;;;;;;;;AAoBT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;4FAEU,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAhC9B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,4BAA4B;AACtC,oBAAA,QAAQ,EAAE,oBAAoB;oBAC9B,eAAe,EAAE,uBAAuB,CAAC,MAAM;oBAC/C,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,sBAAsB;AAC7B,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,mBAAmB,EAAE,2DAA2D;AACjF,qBAAA;AACD,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;AAoBT,EAAA,CAAA;AACF,iBAAA;;;AC9UD;;AAEG;;"}