@caribeng/ui 22.4.0 → 22.5.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 +311 -313
- package/fesm2022/caribeng-ui-account-picker.mjs +533 -0
- package/fesm2022/caribeng-ui-aging.mjs +488 -0
- package/fesm2022/{caribeng-ui-caribe-alert.mjs → caribeng-ui-alert.mjs} +45 -45
- package/fesm2022/caribeng-ui-amount.mjs +249 -0
- package/fesm2022/caribeng-ui-anchor.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-animation-lottie.mjs → caribeng-ui-animation-lottie.mjs} +41 -41
- package/fesm2022/caribeng-ui-audit-log.mjs +323 -0
- package/fesm2022/caribeng-ui-avatar.mjs +2 -2
- package/fesm2022/caribeng-ui-breadcrumb.mjs +13 -3
- package/fesm2022/{caribeng-ui-caribe-button-group.mjs → caribeng-ui-button-group.mjs} +15 -15
- package/fesm2022/caribeng-ui-button.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-card-content.mjs → caribeng-ui-card-content.mjs} +39 -39
- package/fesm2022/{caribeng-ui-caribe-card-move.mjs → caribeng-ui-card-move.mjs} +65 -65
- package/fesm2022/{caribeng-ui-caribe-card-primary.mjs → caribeng-ui-card-primary.mjs} +31 -31
- package/fesm2022/{caribeng-ui-caribe-card-select.mjs → caribeng-ui-card-select.mjs} +67 -67
- package/fesm2022/caribeng-ui-carousel.mjs +2 -2
- package/fesm2022/caribeng-ui-cascadeselect.mjs +45 -9
- package/fesm2022/caribeng-ui-chat.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-coachmark.mjs → caribeng-ui-coachmark.mjs} +85 -85
- package/fesm2022/caribeng-ui-command-palette.mjs +2 -2
- package/fesm2022/caribeng-ui-comments.mjs +864 -0
- package/fesm2022/caribeng-ui-datagrid.mjs +1635 -0
- package/fesm2022/caribeng-ui-dataview.mjs +2 -2
- package/fesm2022/caribeng-ui-datepicker.mjs +2 -2
- package/fesm2022/caribeng-ui-document.mjs +495 -0
- package/fesm2022/{caribeng-ui-caribe-dots-indicator.mjs → caribeng-ui-dots-indicator.mjs} +41 -41
- package/fesm2022/caribeng-ui-dynamic-form.mjs +1581 -0
- package/fesm2022/caribeng-ui-editor.mjs +2303 -1311
- package/fesm2022/{caribeng-ui-caribe-expansion-panel.mjs → caribeng-ui-expansion-panel.mjs} +39 -39
- package/fesm2022/{caribeng-ui-caribe-fab-menu.mjs → caribeng-ui-fab-menu.mjs} +75 -75
- package/fesm2022/caribeng-ui-file-card.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-file-download.mjs → caribeng-ui-file-download.mjs} +63 -63
- package/fesm2022/caribeng-ui-financial-report.mjs +380 -0
- package/fesm2022/{caribeng-ui-caribe-float-menu.mjs → caribeng-ui-float-menu.mjs} +31 -31
- package/fesm2022/caribeng-ui-floatlabel.mjs +2 -2
- package/fesm2022/caribeng-ui-flow.mjs +1508 -0
- package/fesm2022/{caribeng-ui-caribe-footer.mjs → caribeng-ui-footer.mjs} +19 -19
- package/fesm2022/caribeng-ui-gantt.mjs +1094 -0
- package/fesm2022/{caribeng-ui-caribe-header.mjs → caribeng-ui-header.mjs} +49 -49
- package/fesm2022/{caribeng-ui-caribe-icon-button.mjs → caribeng-ui-icon-button.mjs} +23 -23
- package/fesm2022/caribeng-ui-image-cropper.mjs +671 -0
- package/fesm2022/caribeng-ui-import-wizard.mjs +746 -0
- package/fesm2022/caribeng-ui-infinite-scroll.mjs +226 -0
- package/fesm2022/caribeng-ui-input-number.mjs +22 -6
- package/fesm2022/{caribeng-ui-caribe-input-search.mjs → caribeng-ui-input-search.mjs} +65 -65
- package/fesm2022/{caribeng-ui-caribe-input-token.mjs → caribeng-ui-input-token.mjs} +59 -59
- package/fesm2022/caribeng-ui-inputotp.mjs +2 -2
- package/fesm2022/caribeng-ui-journal-entry.mjs +340 -0
- package/fesm2022/caribeng-ui-kanban.mjs +6 -6
- package/fesm2022/caribeng-ui-kpi.mjs +189 -0
- package/fesm2022/{caribeng-ui-caribe-link.mjs → caribeng-ui-link.mjs} +37 -37
- package/fesm2022/caribeng-ui-masonry.mjs +93 -0
- package/fesm2022/caribeng-ui-media-player.mjs +821 -0
- package/fesm2022/caribeng-ui-mentions.mjs +2 -2
- package/fesm2022/caribeng-ui-notification-center.mjs +636 -0
- package/fesm2022/{caribeng-ui-caribe-off-canvas.mjs → caribeng-ui-off-canvas.mjs} +55 -55
- package/fesm2022/{caribeng-ui-caribe-onboarding.mjs → caribeng-ui-onboarding.mjs} +105 -105
- package/fesm2022/caribeng-ui-orderlist.mjs +2 -2
- package/fesm2022/caribeng-ui-pdfviewer.mjs +1755 -25
- package/fesm2022/caribeng-ui-period-picker.mjs +637 -0
- package/fesm2022/caribeng-ui-phone-input.mjs +2 -2
- package/fesm2022/caribeng-ui-picklist.mjs +2 -2
- package/fesm2022/caribeng-ui-pivot.mjs +419 -0
- package/fesm2022/caribeng-ui-pricing.mjs +2 -2
- package/fesm2022/caribeng-ui-rating.mjs +14 -17
- package/fesm2022/caribeng-ui-reconciliation.mjs +386 -0
- package/fesm2022/caribeng-ui-scheduler.mjs +1027 -0
- package/fesm2022/caribeng-ui-select.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-shortcut.mjs → caribeng-ui-shortcut.mjs} +29 -29
- package/fesm2022/caribeng-ui-sidebar.mjs +2 -2
- package/fesm2022/caribeng-ui-signature-pad.mjs +654 -0
- package/fesm2022/{caribeng-ui-caribe-status.mjs → caribeng-ui-status.mjs} +11 -11
- package/fesm2022/{caribeng-ui-caribe-step-indicator.mjs → caribeng-ui-step-indicator.mjs} +53 -53
- package/fesm2022/caribeng-ui-stepper.mjs +2 -2
- package/fesm2022/caribeng-ui-steps.mjs +2 -2
- package/fesm2022/caribeng-ui-table.mjs +323 -15
- package/fesm2022/caribeng-ui-tabmenu.mjs +2 -2
- package/fesm2022/caribeng-ui-tabs.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-tag-button.mjs → caribeng-ui-tag-button.mjs} +25 -25
- package/fesm2022/caribeng-ui-tag.mjs +2 -2
- package/fesm2022/caribeng-ui-tieredmenu.mjs +6 -6
- package/fesm2022/{caribeng-ui-caribe-tracker.mjs → caribeng-ui-tracker.mjs} +29 -29
- package/fesm2022/{caribeng-ui-caribe-transaction-status.mjs → caribeng-ui-transaction-status.mjs} +11 -11
- package/fesm2022/caribeng-ui-treeselect.mjs +44 -9
- package/fesm2022/caribeng-ui-treetable.mjs +236 -17
- package/fesm2022/{caribeng-ui-caribe-voucher.mjs → caribeng-ui-voucher.mjs} +45 -45
- package/fesm2022/caribeng-ui-xlsx.mjs +486 -0
- package/fesm2022/caribeng-ui.mjs +1181 -1
- package/package.json +217 -177
- package/types/caribeng-ui-account-picker.d.ts +142 -0
- package/types/caribeng-ui-aging.d.ts +123 -0
- package/types/{caribeng-ui-caribe-alert.d.ts → caribeng-ui-alert.d.ts} +2 -2
- package/types/caribeng-ui-amount.d.ts +82 -0
- package/types/{caribeng-ui-caribe-animation-lottie.d.ts → caribeng-ui-animation-lottie.d.ts} +2 -2
- package/types/caribeng-ui-audit-log.d.ts +86 -0
- package/types/caribeng-ui-breadcrumb.d.ts +2 -2
- package/types/{caribeng-ui-caribe-button-group.d.ts → caribeng-ui-button-group.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-content.d.ts → caribeng-ui-card-content.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-move.d.ts → caribeng-ui-card-move.d.ts} +1 -1
- package/types/{caribeng-ui-caribe-card-primary.d.ts → caribeng-ui-card-primary.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-select.d.ts → caribeng-ui-card-select.d.ts} +2 -2
- package/types/caribeng-ui-cascadeselect.d.ts +6 -0
- package/types/{caribeng-ui-caribe-coachmark.d.ts → caribeng-ui-coachmark.d.ts} +2 -2
- package/types/caribeng-ui-comments.d.ts +214 -0
- package/types/caribeng-ui-datagrid.d.ts +269 -0
- package/types/caribeng-ui-document.d.ts +138 -0
- package/types/{caribeng-ui-caribe-dots-indicator.d.ts → caribeng-ui-dots-indicator.d.ts} +2 -2
- package/types/caribeng-ui-dynamic-form.d.ts +409 -0
- package/types/caribeng-ui-editor.d.ts +110 -12
- package/types/{caribeng-ui-caribe-expansion-panel.d.ts → caribeng-ui-expansion-panel.d.ts} +1 -1
- package/types/{caribeng-ui-caribe-fab-menu.d.ts → caribeng-ui-fab-menu.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-file-download.d.ts → caribeng-ui-file-download.d.ts} +1 -1
- package/types/caribeng-ui-financial-report.d.ts +102 -0
- package/types/{caribeng-ui-caribe-float-menu.d.ts → caribeng-ui-float-menu.d.ts} +2 -2
- package/types/caribeng-ui-flow.d.ts +228 -0
- package/types/{caribeng-ui-caribe-footer.d.ts → caribeng-ui-footer.d.ts} +2 -2
- package/types/caribeng-ui-gantt.d.ts +244 -0
- package/types/{caribeng-ui-caribe-header.d.ts → caribeng-ui-header.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-icon-button.d.ts → caribeng-ui-icon-button.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-illustration.d.ts → caribeng-ui-illustration.d.ts} +1 -1
- package/types/caribeng-ui-image-cropper.d.ts +169 -0
- package/types/caribeng-ui-import-wizard.d.ts +149 -0
- package/types/caribeng-ui-infinite-scroll.d.ts +75 -0
- package/types/caribeng-ui-input-number.d.ts +1 -1
- package/types/{caribeng-ui-caribe-input-search.d.ts → caribeng-ui-input-search.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-input-token.d.ts → caribeng-ui-input-token.d.ts} +2 -2
- package/types/caribeng-ui-journal-entry.d.ts +110 -0
- package/types/caribeng-ui-kpi.d.ts +64 -0
- package/types/{caribeng-ui-caribe-link.d.ts → caribeng-ui-link.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-logo.d.ts → caribeng-ui-logo.d.ts} +1 -1
- package/types/caribeng-ui-masonry.d.ts +32 -0
- package/types/caribeng-ui-media-player.d.ts +140 -0
- package/types/caribeng-ui-notification-center.d.ts +153 -0
- package/types/{caribeng-ui-caribe-off-canvas.d.ts → caribeng-ui-off-canvas.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-onboarding.d.ts → caribeng-ui-onboarding.d.ts} +2 -2
- package/types/caribeng-ui-pdfviewer.d.ts +245 -5
- package/types/caribeng-ui-period-picker.d.ts +148 -0
- package/types/caribeng-ui-pivot.d.ts +116 -0
- package/types/caribeng-ui-reconciliation.d.ts +109 -0
- package/types/caribeng-ui-scheduler.d.ts +188 -0
- package/types/{caribeng-ui-caribe-shortcut.d.ts → caribeng-ui-shortcut.d.ts} +2 -2
- package/types/caribeng-ui-signature-pad.d.ts +151 -0
- package/types/{caribeng-ui-caribe-status.d.ts → caribeng-ui-status.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-step-indicator.d.ts → caribeng-ui-step-indicator.d.ts} +2 -2
- package/types/caribeng-ui-table.d.ts +66 -2
- package/types/{caribeng-ui-caribe-tag-button.d.ts → caribeng-ui-tag-button.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-tracker.d.ts → caribeng-ui-tracker.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-transaction-status.d.ts → caribeng-ui-transaction-status.d.ts} +2 -2
- package/types/caribeng-ui-treeselect.d.ts +6 -0
- package/types/caribeng-ui-treetable.d.ts +67 -2
- package/types/{caribeng-ui-caribe-voucher.d.ts → caribeng-ui-voucher.d.ts} +2 -2
- package/types/caribeng-ui-xlsx.d.ts +79 -0
- package/types/caribeng-ui.d.ts +711 -2
- package/fesm2022/caribeng-ui-caribe-calendar.mjs +0 -92
- package/fesm2022/caribeng-ui-caribe-circle-loading.mjs +0 -130
- package/fesm2022/caribeng-ui-caribe-data-table.mjs +0 -94
- package/fesm2022/caribeng-ui-caribe-file-select.mjs +0 -88
- package/fesm2022/caribeng-ui-caribe-inline-alert.mjs +0 -100
- package/fesm2022/caribeng-ui-caribe-input-date.mjs +0 -138
- package/fesm2022/caribeng-ui-caribe-input-select.mjs +0 -154
- package/fesm2022/caribeng-ui-caribe-loader.mjs +0 -48
- package/fesm2022/caribeng-ui-caribe-modal.mjs +0 -119
- package/fesm2022/caribeng-ui-caribe-pictogram.mjs +0 -52
- package/fesm2022/caribeng-ui-caribe-pop-over.mjs +0 -104
- package/fesm2022/caribeng-ui-caribe-preloader.mjs +0 -57
- package/fesm2022/caribeng-ui-caribe-progress-bar.mjs +0 -84
- package/fesm2022/caribeng-ui-caribe-stroke.mjs +0 -69
- package/fesm2022/caribeng-ui-caribe-switch.mjs +0 -182
- package/types/caribeng-ui-caribe-calendar.d.ts +0 -27
- package/types/caribeng-ui-caribe-circle-loading.d.ts +0 -28
- package/types/caribeng-ui-caribe-data-table.d.ts +0 -26
- package/types/caribeng-ui-caribe-file-select.d.ts +0 -31
- package/types/caribeng-ui-caribe-inline-alert.d.ts +0 -28
- package/types/caribeng-ui-caribe-input-date.d.ts +0 -40
- package/types/caribeng-ui-caribe-input-select.d.ts +0 -47
- package/types/caribeng-ui-caribe-loader.d.ts +0 -22
- package/types/caribeng-ui-caribe-modal.d.ts +0 -21
- package/types/caribeng-ui-caribe-pictogram.d.ts +0 -15
- package/types/caribeng-ui-caribe-pop-over.d.ts +0 -17
- package/types/caribeng-ui-caribe-preloader.d.ts +0 -24
- package/types/caribeng-ui-caribe-progress-bar.d.ts +0 -28
- package/types/caribeng-ui-caribe-stroke.d.ts +0 -17
- package/types/caribeng-ui-caribe-switch.d.ts +0 -55
- /package/fesm2022/{caribeng-ui-caribe-illustration.mjs → caribeng-ui-illustration.mjs} +0 -0
- /package/fesm2022/{caribeng-ui-caribe-logo.mjs → caribeng-ui-logo.mjs} +0 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, Injector, ViewContainerRef, model, input, booleanAttribute, numberAttribute, output, computed, signal, viewChild, effect, untracked, afterNextRender, DestroyRef, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
+
import { Overlay } from '@angular/cdk/overlay';
|
|
5
|
+
import { TemplatePortal } from '@angular/cdk/portal';
|
|
6
|
+
import { injectCbTranslation, cbFormat, cbRelativeTime } from '@caribeng/ui';
|
|
7
|
+
import { CbAvatar } from '@caribeng/ui/avatar';
|
|
8
|
+
import { CbIconRegistry, CbIcon } from '@caribeng/ui/icon';
|
|
9
|
+
import { bellOff, checkCheck } from '@caribeng/ui/icons';
|
|
10
|
+
|
|
11
|
+
function toTime(date) {
|
|
12
|
+
const t = (date instanceof Date ? date : new Date(date)).getTime();
|
|
13
|
+
return Number.isNaN(t) ? 0 : t;
|
|
14
|
+
}
|
|
15
|
+
/** Inicio del día local de `time`. */
|
|
16
|
+
function startOfDay(time) {
|
|
17
|
+
const d = new Date(time);
|
|
18
|
+
d.setHours(0, 0, 0, 0);
|
|
19
|
+
return d.getTime();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Notificaciones de la más reciente a la más antigua, filtradas y (con `group`) repartidas en
|
|
23
|
+
* Hoy, Ayer y Anteriores. Sin agrupar devuelve un único grupo `earlier`.
|
|
24
|
+
*/
|
|
25
|
+
function groupNotifications(list, filter, group, now) {
|
|
26
|
+
const items = list.filter((n) => filter === 'all' || !n.read).sort((a, b) => toTime(b.date) - toTime(a.date));
|
|
27
|
+
if (!group)
|
|
28
|
+
return items.length ? [{ key: 'earlier', items }] : [];
|
|
29
|
+
const today = startOfDay(now);
|
|
30
|
+
const yesterday = today - 86_400_000;
|
|
31
|
+
const buckets = { today: [], yesterday: [], earlier: [] };
|
|
32
|
+
for (const n of items) {
|
|
33
|
+
const t = toTime(n.date);
|
|
34
|
+
buckets[t >= today ? 'today' : t >= yesterday ? 'yesterday' : 'earlier'].push(n);
|
|
35
|
+
}
|
|
36
|
+
return ['today', 'yesterday', 'earlier'].filter((k) => buckets[k].length).map((key) => ({ key, items: buckets[key] }));
|
|
37
|
+
}
|
|
38
|
+
/** Contador del botón: "99+" a partir de `max`. */
|
|
39
|
+
function badgeText(count, max) {
|
|
40
|
+
return count > max ? `${max}+` : String(count);
|
|
41
|
+
}
|
|
42
|
+
/** Iniciales de un nombre ("Ana López" → "AL"). */
|
|
43
|
+
function initialsOf(name) {
|
|
44
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
45
|
+
return ((parts[0]?.[0] ?? '') + (parts.length > 1 ? parts[parts.length - 1][0] : '')).toUpperCase();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const SEVERITY_ICON = {
|
|
49
|
+
info: 'info',
|
|
50
|
+
success: 'circle-check',
|
|
51
|
+
warning: 'triangle-alert',
|
|
52
|
+
danger: 'circle-x',
|
|
53
|
+
};
|
|
54
|
+
let nextUid = 0;
|
|
55
|
+
/**
|
|
56
|
+
* Centro de notificaciones de CaribeNG: campana con el número de avisos sin leer que abre un
|
|
57
|
+
* panel con la lista agrupada por fecha (Hoy, Ayer, Anteriores), filtro Todas / No leídas,
|
|
58
|
+
* marcar como leída (una o todas), eliminar y acciones propias en cada aviso. Con `inline` el
|
|
59
|
+
* panel se pinta en la página, sin campana.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```html
|
|
63
|
+
* <cb-notification-center [(notifications)]="avisos" (itemClick)="abrir($event)" />
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
class CbNotificationCenter {
|
|
67
|
+
constructor() {
|
|
68
|
+
this.t = injectCbTranslation();
|
|
69
|
+
this.fmt = cbFormat;
|
|
70
|
+
this.host = inject(ElementRef);
|
|
71
|
+
this.injector = inject(Injector);
|
|
72
|
+
this.overlay = inject(Overlay);
|
|
73
|
+
this.vcr = inject(ViewContainerRef);
|
|
74
|
+
this.panelId = `cb-nc-${++nextUid}`;
|
|
75
|
+
/** Avisos (el panel los ordena del más reciente al más antiguo). Se actualiza al leer o eliminar. */
|
|
76
|
+
this.notifications = model([], /* @ts-ignore */
|
|
77
|
+
...(ngDevMode ? [{ debugName: "notifications" }] : /* istanbul ignore next */ []));
|
|
78
|
+
/** Todas o solo las no leídas. */
|
|
79
|
+
this.filter = model('all', /* @ts-ignore */
|
|
80
|
+
...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
|
|
81
|
+
/** Panel abierto (sin `inline`). */
|
|
82
|
+
this.open = model(false, /* @ts-ignore */
|
|
83
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
84
|
+
/** Pinta el panel en la página, sin campana ni ventana flotante. */
|
|
85
|
+
this.inline = input(false, { ...(ngDevMode ? { debugName: "inline" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
86
|
+
/** Agrupa por fecha: Hoy, Ayer y Anteriores. */
|
|
87
|
+
this.groupByDate = input(true, { ...(ngDevMode ? { debugName: "groupByDate" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
88
|
+
/** Muestra el botón de eliminar en cada aviso. */
|
|
89
|
+
this.removable = input(true, { ...(ngDevMode ? { debugName: "removable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
90
|
+
/** Cierra el panel al elegir un aviso. */
|
|
91
|
+
this.closeOnSelect = input(true, { ...(ngDevMode ? { debugName: "closeOnSelect" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
92
|
+
/**
|
|
93
|
+
* Anuncia a los lectores de pantalla los avisos nuevos sin leer. Si la misma lista se muestra en
|
|
94
|
+
* dos centros (la campana y una página), desactívalo en uno para no oírlo dos veces.
|
|
95
|
+
*/
|
|
96
|
+
this.announceNew = input(true, { ...(ngDevMode ? { debugName: "announceNew" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
97
|
+
/** Muestra el pie con "Ver todas" (`viewAll`). */
|
|
98
|
+
this.showViewAll = input(false, { ...(ngDevMode ? { debugName: "showViewAll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
99
|
+
/** A partir de este número, la campana muestra "99+". */
|
|
100
|
+
this.max = input(99, { ...(ngDevMode ? { debugName: "max" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
101
|
+
/** Título del panel (por defecto, "Notificaciones"). No es `title` para no dar un tooltip al componente. */
|
|
102
|
+
this.heading = input(undefined, /* @ts-ignore */
|
|
103
|
+
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
104
|
+
/** Nivel del título (los grupos usan el siguiente). */
|
|
105
|
+
this.headingLevel = input(2, { ...(ngDevMode ? { debugName: "headingLevel" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
106
|
+
this.emptyMessage = input(undefined, /* @ts-ignore */
|
|
107
|
+
...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
|
|
108
|
+
this.panelWidth = input('24rem', /* @ts-ignore */
|
|
109
|
+
...(ngDevMode ? [{ debugName: "panelWidth" }] : /* istanbul ignore next */ []));
|
|
110
|
+
/** Alto máximo de la lista (con scroll). */
|
|
111
|
+
this.maxHeight = input('26rem', /* @ts-ignore */
|
|
112
|
+
...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
|
|
113
|
+
/** Aviso elegido (ya marcado como leído). */
|
|
114
|
+
this.itemClick = output();
|
|
115
|
+
this.actionClick = output();
|
|
116
|
+
/** Un aviso pasó a leído (`read: true`) o a no leído. */
|
|
117
|
+
this.readChange = output();
|
|
118
|
+
this.markAll = output();
|
|
119
|
+
this.itemRemove = output();
|
|
120
|
+
this.viewAll = output();
|
|
121
|
+
this.unread = computed(() => this.notifications().filter((n) => !n.read).length, /* @ts-ignore */
|
|
122
|
+
...(ngDevMode ? [{ debugName: "unread" }] : /* istanbul ignore next */ []));
|
|
123
|
+
this.badge = computed(() => badgeText(this.unread(), this.max()), /* @ts-ignore */
|
|
124
|
+
...(ngDevMode ? [{ debugName: "badge" }] : /* istanbul ignore next */ []));
|
|
125
|
+
this.bellLabel = computed(() => {
|
|
126
|
+
const t = this.t();
|
|
127
|
+
return this.unread() ? cbFormat(t.notificationsBellUnread, this.unread()) : t.notificationsTitle;
|
|
128
|
+
}, /* @ts-ignore */
|
|
129
|
+
...(ngDevMode ? [{ debugName: "bellLabel" }] : /* istanbul ignore next */ []));
|
|
130
|
+
this.now = signal(Date.now(), /* @ts-ignore */
|
|
131
|
+
...(ngDevMode ? [{ debugName: "now" }] : /* istanbul ignore next */ []));
|
|
132
|
+
this.groups = computed(() => groupNotifications(this.notifications(), this.filter(), this.groupByDate(), this.now()), /* @ts-ignore */
|
|
133
|
+
...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
|
|
134
|
+
this.announcement = signal('', /* @ts-ignore */
|
|
135
|
+
...(ngDevMode ? [{ debugName: "announcement" }] : /* istanbul ignore next */ []));
|
|
136
|
+
this.panelTpl = viewChild.required('panelTpl');
|
|
137
|
+
this.bell = viewChild('bell', /* @ts-ignore */
|
|
138
|
+
...(ngDevMode ? [{ debugName: "bell" }] : /* istanbul ignore next */ []));
|
|
139
|
+
this.overlayRef = null;
|
|
140
|
+
/** El foco está (o estaba, si su elemento desapareció) dentro del panel. */
|
|
141
|
+
this.focusInside = false;
|
|
142
|
+
this.positions = [
|
|
143
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 8 },
|
|
144
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 8 },
|
|
145
|
+
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -8 },
|
|
146
|
+
];
|
|
147
|
+
this.announceFlip = false;
|
|
148
|
+
const registry = inject(CbIconRegistry);
|
|
149
|
+
for (const [name, body] of Object.entries({ 'check-check': checkCheck, 'bell-off': bellOff })) {
|
|
150
|
+
if (!registry.has(name))
|
|
151
|
+
registry.register({ [name]: body });
|
|
152
|
+
}
|
|
153
|
+
// Abrir y cerrar el panel flotante cuando cambia `open` (también desde fuera).
|
|
154
|
+
effect(() => {
|
|
155
|
+
const open = this.open() && !this.inline();
|
|
156
|
+
untracked(() => (open ? this.attach() : this.detach()));
|
|
157
|
+
});
|
|
158
|
+
// Foco: al título del panel al abrir. Al cerrar, si el foco se quedó en ninguna parte (estaba
|
|
159
|
+
// en el panel, que ya no existe), vuelve a la campana; no se usa "el elemento enfocado antes"
|
|
160
|
+
// porque Safari no enfoca un botón al pulsarlo.
|
|
161
|
+
let wasOpen = false;
|
|
162
|
+
effect(() => {
|
|
163
|
+
const open = this.open() && !this.inline();
|
|
164
|
+
if (open === wasOpen)
|
|
165
|
+
return;
|
|
166
|
+
wasOpen = open;
|
|
167
|
+
afterNextRender(() => {
|
|
168
|
+
if (open) {
|
|
169
|
+
this.overlayRef?.overlayElement.querySelector('.cb-nc__title')?.focus();
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const active = this.host.nativeElement.ownerDocument.activeElement;
|
|
173
|
+
if (!active || active === active.ownerDocument.body)
|
|
174
|
+
this.bell()?.nativeElement.focus();
|
|
175
|
+
}
|
|
176
|
+
}, { injector: this.injector });
|
|
177
|
+
});
|
|
178
|
+
// Anuncia los avisos nuevos sin leer (no los que ya estaban al empezar).
|
|
179
|
+
let known = null;
|
|
180
|
+
effect(() => {
|
|
181
|
+
const list = this.notifications();
|
|
182
|
+
const ids = new Set(list.map((n) => n.id));
|
|
183
|
+
if (known) {
|
|
184
|
+
const fresh = list.filter((n) => !n.read && !known.has(n.id));
|
|
185
|
+
if (fresh.length && untracked(this.announceNew)) {
|
|
186
|
+
untracked(() => this.announce(fresh.length === 1 ? cbFormat(this.t().notificationsNew, fresh[0].title) : cbFormat(this.t().notificationsNewMany, fresh.length)));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
known = ids;
|
|
190
|
+
// Si la app quitó el aviso que tenía el foco (p. ej. tras una acción), el foco vuelve al título.
|
|
191
|
+
afterNextRender(() => {
|
|
192
|
+
const active = this.host.nativeElement.ownerDocument.activeElement;
|
|
193
|
+
if (this.focusInside && (!active || active === active.ownerDocument.body)) {
|
|
194
|
+
this.panelRoot()?.querySelector(`#${this.panelId}-title`)?.focus();
|
|
195
|
+
}
|
|
196
|
+
}, { injector: this.injector });
|
|
197
|
+
});
|
|
198
|
+
const destroyRef = inject(DestroyRef);
|
|
199
|
+
afterNextRender(() => {
|
|
200
|
+
const timer = setInterval(() => this.now.set(Date.now()), 60_000);
|
|
201
|
+
destroyRef.onDestroy(() => clearInterval(timer));
|
|
202
|
+
});
|
|
203
|
+
destroyRef.onDestroy(() => this.detach());
|
|
204
|
+
}
|
|
205
|
+
// --- API pública ---
|
|
206
|
+
toggle() {
|
|
207
|
+
this.open.update((o) => !o);
|
|
208
|
+
}
|
|
209
|
+
show() {
|
|
210
|
+
this.open.set(true);
|
|
211
|
+
}
|
|
212
|
+
hide() {
|
|
213
|
+
this.open.set(false);
|
|
214
|
+
}
|
|
215
|
+
// --- Plantilla ---
|
|
216
|
+
initials(name) {
|
|
217
|
+
return initialsOf(name);
|
|
218
|
+
}
|
|
219
|
+
iconOf(n) {
|
|
220
|
+
return n.icon || SEVERITY_ICON[n.severity ?? 'info'];
|
|
221
|
+
}
|
|
222
|
+
groupLabel(key) {
|
|
223
|
+
const t = this.t();
|
|
224
|
+
return key === 'today' ? t.notificationsToday : key === 'yesterday' ? t.notificationsYesterday : t.notificationsEarlier;
|
|
225
|
+
}
|
|
226
|
+
itemId(n) {
|
|
227
|
+
return `${this.panelId}-${n.id.replace(/[^\w-]/g, '_')}`;
|
|
228
|
+
}
|
|
229
|
+
iso(date) {
|
|
230
|
+
const time = toTime(date);
|
|
231
|
+
return time ? new Date(time).toISOString() : '';
|
|
232
|
+
}
|
|
233
|
+
full(date) {
|
|
234
|
+
const time = toTime(date);
|
|
235
|
+
return time ? new Intl.DateTimeFormat(this.t().intlLocale, { dateStyle: 'full', timeStyle: 'short' }).format(time) : '';
|
|
236
|
+
}
|
|
237
|
+
rel(date) {
|
|
238
|
+
const time = toTime(date);
|
|
239
|
+
return time ? cbRelativeTime(time, this.now(), this.t().intlLocale, this.t().notificationsJustNow) : '';
|
|
240
|
+
}
|
|
241
|
+
// --- Acciones ---
|
|
242
|
+
select(n) {
|
|
243
|
+
const item = n.read ? n : this.patch(n, { read: true });
|
|
244
|
+
if (!n.read)
|
|
245
|
+
this.readChange.emit(item);
|
|
246
|
+
this.itemClick.emit(item);
|
|
247
|
+
if (this.closeOnSelect() && !this.inline())
|
|
248
|
+
this.hide();
|
|
249
|
+
}
|
|
250
|
+
runAction(n, action) {
|
|
251
|
+
const item = n.read ? n : this.patch(n, { read: true });
|
|
252
|
+
if (!n.read)
|
|
253
|
+
this.readChange.emit(item);
|
|
254
|
+
this.actionClick.emit({ notification: item, action });
|
|
255
|
+
}
|
|
256
|
+
setRead(n, read) {
|
|
257
|
+
const item = this.patch(n, { read });
|
|
258
|
+
this.readChange.emit(item);
|
|
259
|
+
this.announce(read ? this.t().notificationsMarkedRead : this.t().notificationsMarkedUnread);
|
|
260
|
+
// Con el filtro "No leídas", el aviso desaparece: el foco pasa al siguiente.
|
|
261
|
+
if (read && this.filter() === 'unread')
|
|
262
|
+
this.focusAfterRemoval(n);
|
|
263
|
+
}
|
|
264
|
+
markAllRead() {
|
|
265
|
+
if (!this.unread())
|
|
266
|
+
return;
|
|
267
|
+
this.notifications.update((list) => list.map((n) => (n.read ? n : { ...n, read: true })));
|
|
268
|
+
this.markAll.emit();
|
|
269
|
+
this.announce(this.t().notificationsMarkedAllRead);
|
|
270
|
+
this.focusLater(`#${this.panelId}-title`);
|
|
271
|
+
}
|
|
272
|
+
remove(n) {
|
|
273
|
+
this.focusAfterRemoval(n);
|
|
274
|
+
this.notifications.update((list) => list.filter((x) => x.id !== n.id));
|
|
275
|
+
this.itemRemove.emit(n);
|
|
276
|
+
this.announce(this.t().notificationsRemoved);
|
|
277
|
+
}
|
|
278
|
+
onViewAll() {
|
|
279
|
+
this.viewAll.emit();
|
|
280
|
+
if (!this.inline())
|
|
281
|
+
this.hide();
|
|
282
|
+
}
|
|
283
|
+
/** Escape cierra; Tab fuera del panel lo cierra y devuelve el foco a la campana. */
|
|
284
|
+
onPanelKeydown(event) {
|
|
285
|
+
if (this.inline())
|
|
286
|
+
return;
|
|
287
|
+
if (event.key === 'Escape') {
|
|
288
|
+
event.preventDefault();
|
|
289
|
+
this.hide();
|
|
290
|
+
}
|
|
291
|
+
else if (event.key === 'Tab') {
|
|
292
|
+
const panel = event.currentTarget;
|
|
293
|
+
const focusables = Array.from(panel.querySelectorAll('button:not(:disabled), [href], [tabindex="0"]'));
|
|
294
|
+
const first = focusables[0];
|
|
295
|
+
const last = focusables[focusables.length - 1];
|
|
296
|
+
const active = panel.ownerDocument.activeElement;
|
|
297
|
+
if ((!event.shiftKey && active === last) || (event.shiftKey && (active === first || active === panel.querySelector('.cb-nc__title')))) {
|
|
298
|
+
event.preventDefault();
|
|
299
|
+
this.hide();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/** Sale el foco hacia otro elemento de la página (no cuando su elemento desaparece). */
|
|
304
|
+
onPanelFocusOut(event) {
|
|
305
|
+
const next = event.relatedTarget;
|
|
306
|
+
if (next && !event.currentTarget.contains(next))
|
|
307
|
+
this.focusInside = false;
|
|
308
|
+
}
|
|
309
|
+
// --- Internos ---
|
|
310
|
+
patch(n, change) {
|
|
311
|
+
const item = { ...n, ...change };
|
|
312
|
+
this.notifications.update((list) => list.map((x) => (x.id === n.id ? item : x)));
|
|
313
|
+
return item;
|
|
314
|
+
}
|
|
315
|
+
/** Antes de quitar un aviso de la vista: foco al siguiente (o al anterior, o al título). */
|
|
316
|
+
focusAfterRemoval(n) {
|
|
317
|
+
const root = this.panelRoot();
|
|
318
|
+
const items = Array.from(root?.querySelectorAll('.cb-nc__item') ?? []);
|
|
319
|
+
const i = items.findIndex((el) => el.dataset['id'] === n.id);
|
|
320
|
+
const nextId = (items[i + 1] ?? items[i - 1])?.dataset['id'];
|
|
321
|
+
afterNextRender(() => {
|
|
322
|
+
const root = this.panelRoot();
|
|
323
|
+
const next = Array.from(root?.querySelectorAll('.cb-nc__item') ?? []).find((el) => el.dataset['id'] === nextId);
|
|
324
|
+
(next?.querySelector('.cb-nc__main') ?? root?.querySelector(`#${this.panelId}-title`))?.focus();
|
|
325
|
+
}, { injector: this.injector });
|
|
326
|
+
}
|
|
327
|
+
panelRoot() {
|
|
328
|
+
return this.inline() ? this.host.nativeElement : (this.overlayRef?.overlayElement ?? null);
|
|
329
|
+
}
|
|
330
|
+
attach() {
|
|
331
|
+
const origin = this.bell()?.nativeElement;
|
|
332
|
+
if (this.overlayRef || !origin)
|
|
333
|
+
return;
|
|
334
|
+
this.overlayRef = this.overlay.create({
|
|
335
|
+
positionStrategy: this.overlay.position().flexibleConnectedTo(origin).withPositions(this.positions).withPush(true).withViewportMargin(8),
|
|
336
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
337
|
+
hasBackdrop: true,
|
|
338
|
+
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
339
|
+
panelClass: 'cb-nc-overlay',
|
|
340
|
+
maxWidth: 'calc(100vw - 16px)',
|
|
341
|
+
});
|
|
342
|
+
this.overlayRef.attach(new TemplatePortal(this.panelTpl(), this.vcr));
|
|
343
|
+
this.overlayRef.backdropClick().subscribe(() => this.hide());
|
|
344
|
+
}
|
|
345
|
+
detach() {
|
|
346
|
+
this.overlayRef?.dispose();
|
|
347
|
+
this.overlayRef = null;
|
|
348
|
+
this.focusInside = false;
|
|
349
|
+
}
|
|
350
|
+
/** Un espacio duro alterno hace que el mismo texto cuente como cambio y se vuelva a anunciar. */
|
|
351
|
+
announce(text) {
|
|
352
|
+
this.announceFlip = !this.announceFlip;
|
|
353
|
+
this.announcement.set(this.announceFlip ? text : `${text} `);
|
|
354
|
+
}
|
|
355
|
+
focusLater(selector) {
|
|
356
|
+
afterNextRender(() => this.panelRoot()?.querySelector(selector)?.focus(), { injector: this.injector });
|
|
357
|
+
}
|
|
358
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbNotificationCenter, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
359
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbNotificationCenter, isStandalone: true, selector: "cb-notification-center", inputs: { notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, groupByDate: { classPropertyName: "groupByDate", publicName: "groupByDate", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, announceNew: { classPropertyName: "announceNew", publicName: "announceNew", isSignal: true, isRequired: false, transformFunction: null }, showViewAll: { classPropertyName: "showViewAll", publicName: "showViewAll", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { notifications: "notificationsChange", filter: "filterChange", open: "openChange", itemClick: "itemClick", actionClick: "actionClick", readChange: "readChange", markAll: "markAll", itemRemove: "itemRemove", viewAll: "viewAll" }, host: { properties: { "class.cb-notification-center--inline": "inline()" }, classAttribute: "cb-notification-center" }, viewQueries: [{ propertyName: "panelTpl", first: true, predicate: ["panelTpl"], descendants: true, isSignal: true }, { propertyName: "bell", first: true, predicate: ["bell"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
360
|
+
@if (inline()) {
|
|
361
|
+
<ng-container [ngTemplateOutlet]="panelTpl" />
|
|
362
|
+
} @else {
|
|
363
|
+
<button
|
|
364
|
+
#bell
|
|
365
|
+
type="button"
|
|
366
|
+
class="cb-nc__bell"
|
|
367
|
+
[attr.aria-label]="bellLabel()"
|
|
368
|
+
aria-haspopup="dialog"
|
|
369
|
+
[attr.aria-expanded]="open()"
|
|
370
|
+
[attr.aria-controls]="open() ? panelId : null"
|
|
371
|
+
(click)="toggle()"
|
|
372
|
+
>
|
|
373
|
+
<cb-icon name="bell" [size]="20" aria-hidden="true" />
|
|
374
|
+
@if (unread()) {
|
|
375
|
+
<span class="cb-nc__badge" aria-hidden="true">{{ badge() }}</span>
|
|
376
|
+
}
|
|
377
|
+
</button>
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
<div class="cb-nc__sr" aria-live="polite">{{ announcement() }}</div>
|
|
381
|
+
|
|
382
|
+
<ng-template #panelTpl>
|
|
383
|
+
<div
|
|
384
|
+
class="cb-nc__panel"
|
|
385
|
+
[id]="panelId"
|
|
386
|
+
[attr.role]="inline() ? 'region' : 'dialog'"
|
|
387
|
+
[attr.aria-labelledby]="panelId + '-title'"
|
|
388
|
+
[style.width]="inline() ? null : panelWidth()"
|
|
389
|
+
(keydown)="onPanelKeydown($event)"
|
|
390
|
+
(focusin)="focusInside = true"
|
|
391
|
+
(focusout)="onPanelFocusOut($event)"
|
|
392
|
+
>
|
|
393
|
+
<div class="cb-nc__header">
|
|
394
|
+
<span class="cb-nc__title" role="heading" [attr.aria-level]="headingLevel()" [id]="panelId + '-title'" tabindex="-1">
|
|
395
|
+
{{ heading() ?? t().notificationsTitle }}
|
|
396
|
+
</span>
|
|
397
|
+
<button type="button" class="cb-nc__link" [disabled]="!unread()" (click)="markAllRead()">
|
|
398
|
+
<cb-icon name="check-check" [size]="16" aria-hidden="true" />
|
|
399
|
+
{{ t().notificationsMarkAllRead }}
|
|
400
|
+
</button>
|
|
401
|
+
</div>
|
|
402
|
+
|
|
403
|
+
<div class="cb-nc__filter" role="group" [attr.aria-label]="t().notificationsShow">
|
|
404
|
+
<button type="button" class="cb-nc__filter-btn" [attr.aria-pressed]="filter() === 'all'" (click)="filter.set('all')">
|
|
405
|
+
{{ t().notificationsAll }}
|
|
406
|
+
</button>
|
|
407
|
+
<button type="button" class="cb-nc__filter-btn" [attr.aria-pressed]="filter() === 'unread'" (click)="filter.set('unread')">
|
|
408
|
+
{{ t().notificationsUnread }}
|
|
409
|
+
@if (unread()) {
|
|
410
|
+
<span class="cb-nc__count">{{ unread() }}</span>
|
|
411
|
+
}
|
|
412
|
+
</button>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
<div class="cb-nc__body" [style.max-height]="maxHeight()">
|
|
416
|
+
@for (g of groups(); track g.key) {
|
|
417
|
+
@if (groupByDate()) {
|
|
418
|
+
<span class="cb-nc__group" role="heading" [attr.aria-level]="headingLevel() + 1" [id]="panelId + '-' + g.key">{{ groupLabel(g.key) }}</span>
|
|
419
|
+
}
|
|
420
|
+
<ul class="cb-nc__list" [attr.aria-labelledby]="groupByDate() ? panelId + '-' + g.key : panelId + '-title'">
|
|
421
|
+
@for (n of g.items; track n.id) {
|
|
422
|
+
<li class="cb-nc__item" [class.cb-nc__item--unread]="!n.read" [attr.data-id]="n.id">
|
|
423
|
+
<span class="cb-nc__media" aria-hidden="true">
|
|
424
|
+
@if (n.person; as p) {
|
|
425
|
+
<cb-avatar [image]="p.image ?? ''" [label]="initials(p.name)" [size]="36" />
|
|
426
|
+
} @else {
|
|
427
|
+
<span class="cb-nc__icon" [attr.data-severity]="n.severity || 'info'">
|
|
428
|
+
<cb-icon [name]="iconOf(n)" [size]="18" />
|
|
429
|
+
</span>
|
|
430
|
+
}
|
|
431
|
+
</span>
|
|
432
|
+
<div class="cb-nc__content">
|
|
433
|
+
<button type="button" class="cb-nc__main" [attr.aria-describedby]="itemId(n) + '-time'" (click)="select(n)">
|
|
434
|
+
@if (!n.read) {
|
|
435
|
+
<span class="cb-nc__sr">{{ t().notificationsUnreadItem }}: </span>
|
|
436
|
+
}
|
|
437
|
+
<span class="cb-nc__item-title">{{ n.title }}</span>
|
|
438
|
+
@if (n.text) {
|
|
439
|
+
<span class="cb-nc__text">{{ n.text }}</span>
|
|
440
|
+
}
|
|
441
|
+
</button>
|
|
442
|
+
<time class="cb-nc__time" [id]="itemId(n) + '-time'" [attr.datetime]="iso(n.date)" [attr.title]="full(n.date)">{{ rel(n.date) }}</time>
|
|
443
|
+
@if (n.actions?.length) {
|
|
444
|
+
<div class="cb-nc__actions">
|
|
445
|
+
@for (a of n.actions; track a.id) {
|
|
446
|
+
<button type="button" class="cb-nc__action" [class.cb-nc__action--primary]="a.severity === 'primary'" (click)="runAction(n, a)">
|
|
447
|
+
{{ a.label }}
|
|
448
|
+
</button>
|
|
449
|
+
}
|
|
450
|
+
</div>
|
|
451
|
+
}
|
|
452
|
+
</div>
|
|
453
|
+
@if (!n.read) {
|
|
454
|
+
<span class="cb-nc__dot" aria-hidden="true"></span>
|
|
455
|
+
}
|
|
456
|
+
<div class="cb-nc__tools">
|
|
457
|
+
<button
|
|
458
|
+
type="button"
|
|
459
|
+
class="cb-nc__tool"
|
|
460
|
+
[attr.aria-label]="fmt(n.read ? t().notificationsMarkUnread : t().notificationsMarkRead, n.title)"
|
|
461
|
+
[attr.title]="n.read ? t().notificationsMarkUnreadShort : t().notificationsMarkReadShort"
|
|
462
|
+
(click)="setRead(n, !n.read)"
|
|
463
|
+
>
|
|
464
|
+
<cb-icon [name]="n.read ? 'mail' : 'check'" [size]="15" aria-hidden="true" />
|
|
465
|
+
</button>
|
|
466
|
+
@if (removable()) {
|
|
467
|
+
<button type="button" class="cb-nc__tool" [attr.aria-label]="fmt(t().removeItem, n.title)" [attr.title]="t().remove" (click)="remove(n)">
|
|
468
|
+
<cb-icon name="x" [size]="15" aria-hidden="true" />
|
|
469
|
+
</button>
|
|
470
|
+
}
|
|
471
|
+
</div>
|
|
472
|
+
</li>
|
|
473
|
+
}
|
|
474
|
+
</ul>
|
|
475
|
+
} @empty {
|
|
476
|
+
<div class="cb-nc__empty">
|
|
477
|
+
<cb-icon name="bell-off" [size]="28" aria-hidden="true" />
|
|
478
|
+
<p>{{ filter() === 'unread' && notifications().length ? t().notificationsAllRead : (emptyMessage() ?? t().notificationsEmpty) }}</p>
|
|
479
|
+
</div>
|
|
480
|
+
}
|
|
481
|
+
</div>
|
|
482
|
+
|
|
483
|
+
@if (showViewAll()) {
|
|
484
|
+
<div class="cb-nc__footer">
|
|
485
|
+
<button type="button" class="cb-nc__link" (click)="onViewAll()">{{ t().notificationsViewAll }}</button>
|
|
486
|
+
</div>
|
|
487
|
+
}
|
|
488
|
+
</div>
|
|
489
|
+
</ng-template>
|
|
490
|
+
`, isInline: true, styles: [".cb-notification-center{display:inline-block;position:relative;color:var(--cb-color-text);font-family:var(--cb-font-sans)}.cb-notification-center--inline{display:block}.cb-nc__bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:0;border-radius:var(--cb-radius-full, 999px);background:transparent;color:var(--cb-color-text);cursor:pointer}.cb-nc__bell:hover,.cb-nc__bell[aria-expanded=true]{background:var(--cb-color-surface-hover)}.cb-nc__badge{position:absolute;top:.125rem;right:.125rem;min-width:1.125rem;height:1.125rem;padding:0 .25rem;box-sizing:border-box;border:2px solid var(--cb-color-bg, #fff);border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-danger);color:var(--cb-color-danger-contrast, #fff);font-size:.625rem;font-weight:var(--cb-font-weight-semibold, 600);line-height:.875rem;text-align:center}.cb-nc__panel{display:flex;flex-direction:column;box-sizing:border-box;max-width:100%;border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-lg, 8px);background:var(--cb-color-surface-raised, var(--cb-color-surface));color:var(--cb-color-text);font-family:var(--cb-font-sans);font-size:var(--cb-text-sm, .875rem)}.cb-nc-overlay .cb-nc__panel{box-shadow:var(--cb-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .15))}.cb-nc__header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem;padding:.875rem 1rem .5rem}.cb-nc__title{font-size:var(--cb-text-base, 1rem);font-weight:var(--cb-font-weight-semibold, 600)}.cb-nc__title:focus{outline:none}.cb-nc__title:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-nc__link{display:inline-flex;align-items:center;gap:.25rem;padding:.25rem .375rem;border:0;border-radius:var(--cb-radius-sm, 4px);background:transparent;color:var(--cb-color-primary);font:inherit;font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500);cursor:pointer}.cb-nc__link:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-nc__link:disabled{color:var(--cb-color-text-muted);cursor:default}.cb-nc__filter{display:flex;gap:.25rem;padding:0 1rem .5rem;border-bottom:1px solid var(--cb-color-border)}.cb-nc__filter-btn{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .625rem;border:0;border-radius:var(--cb-radius-full, 999px);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500);cursor:pointer}.cb-nc__filter-btn:hover{color:var(--cb-color-text)}.cb-nc__filter-btn[aria-pressed=true]{background:var(--cb-color-surface-hover);color:var(--cb-color-text)}.cb-nc__count{min-width:1.125rem;padding:0 .3125rem;box-sizing:border-box;border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-primary);color:var(--cb-color-primary-contrast, #fff);font-size:.625rem;line-height:1.125rem;text-align:center}.cb-nc__body{overflow-y:auto;overscroll-behavior:contain}.cb-nc__group{display:block;padding:.75rem 1rem .25rem;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-semibold, 600);letter-spacing:.02em;text-transform:uppercase}.cb-nc__list{margin:0;padding:0;list-style:none}.cb-nc__item{display:flex;gap:.75rem;padding:.75rem 1rem}.cb-nc__item+.cb-nc__item{border-top:1px solid var(--cb-color-border)}.cb-nc__item--unread{background:color-mix(in srgb,var(--cb-color-primary) 6%,transparent)}.cb-nc__item:hover{background:color-mix(in srgb,var(--cb-color-text) 5%,transparent)}.cb-nc__media{flex:none}.cb-nc__icon{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:var(--cb-radius-full, 999px);--_c: var(--cb-color-info);background:color-mix(in srgb,var(--_c) 14%,transparent);color:var(--_c)}.cb-nc__icon[data-severity=success]{--_c: var(--cb-color-success)}.cb-nc__icon[data-severity=warning]{--_c: var(--cb-color-warning)}.cb-nc__icon[data-severity=danger]{--_c: var(--cb-color-danger)}.cb-nc__content{display:flex;flex:1;flex-direction:column;gap:.125rem;min-width:0}.cb-nc__main{display:flex;flex-direction:column;gap:.125rem;padding:0;border:0;border-radius:var(--cb-radius-sm, 4px);background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.cb-nc__item{position:relative}.cb-nc__main:after{content:\"\";position:absolute;inset:0}.cb-nc__tools,.cb-nc__actions,.cb-nc__time{position:relative;z-index:1}.cb-nc__item-title{font-weight:var(--cb-font-weight-medium, 500);overflow-wrap:anywhere}.cb-nc__item--unread .cb-nc__item-title{font-weight:var(--cb-font-weight-semibold, 600)}.cb-nc__text{display:-webkit-box;overflow:hidden;color:var(--cb-color-text-muted);-webkit-box-orient:vertical;-webkit-line-clamp:2}.cb-nc__time{align-self:flex-start;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs, .75rem)}.cb-nc__actions{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.375rem}.cb-nc__action{min-height:1.75rem;padding:0 .75rem;border:1px solid var(--cb-color-border-strong, var(--cb-color-border));border-radius:var(--cb-radius-md, 6px);background:var(--cb-color-surface-raised, transparent);color:var(--cb-color-text);font:inherit;font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500);cursor:pointer}.cb-nc__action:hover{background:var(--cb-color-surface-hover)}.cb-nc__action--primary{border-color:var(--cb-color-primary);background:var(--cb-color-primary);color:var(--cb-color-primary-contrast, #fff)}.cb-nc__action--primary:hover{background:var(--cb-color-primary-700, var(--cb-color-primary))}.cb-nc__tools{position:absolute;top:.5rem;right:.75rem;display:flex;gap:.125rem;padding:.125rem;border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-surface-raised, var(--cb-color-surface));box-shadow:var(--cb-shadow-sm, 0 1px 2px rgba(0, 0, 0, .08));opacity:0}.cb-nc__dot{flex:none;width:.5rem;height:.5rem;margin:.375rem 0 0;border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-primary)}.cb-nc__tool{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border:0;border-radius:var(--cb-radius-full, 999px);background:transparent;color:var(--cb-color-text-muted);cursor:pointer}.cb-nc__item:hover .cb-nc__tools,.cb-nc__item:focus-within .cb-nc__tools{opacity:1}@media(hover:none){.cb-nc__tools{position:static;align-self:flex-start;border:0;box-shadow:none;background:transparent;opacity:1}}.cb-nc__tool:hover{background:var(--cb-color-surface-active, var(--cb-color-border));color:var(--cb-color-text)}.cb-nc__empty{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding:2rem 1rem;color:var(--cb-color-text-muted);text-align:center}.cb-nc__empty p{margin:0}.cb-nc__footer{display:flex;justify-content:center;padding:.5rem;border-top:1px solid var(--cb-color-border)}.cb-nc__bell:focus-visible,.cb-nc__link:focus-visible,.cb-nc__filter-btn:focus-visible,.cb-nc__action:focus-visible,.cb-nc__tool:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:1px}.cb-nc__main:focus-visible{outline:none}.cb-nc__item:has(.cb-nc__main:focus-visible){outline:2px solid var(--cb-color-focus-ring);outline-offset:-2px}.cb-nc__sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CbAvatar, selector: "cb-avatar", inputs: ["image", "label", "icon", "size", "shape", "severity", "ariaLabel"] }, { kind: "component", type: CbIcon, selector: "cb-icon", inputs: ["name", "size", "spin", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
491
|
+
}
|
|
492
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbNotificationCenter, decorators: [{
|
|
493
|
+
type: Component,
|
|
494
|
+
args: [{ selector: 'cb-notification-center', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, CbAvatar, CbIcon], host: { class: 'cb-notification-center', '[class.cb-notification-center--inline]': 'inline()' }, template: `
|
|
495
|
+
@if (inline()) {
|
|
496
|
+
<ng-container [ngTemplateOutlet]="panelTpl" />
|
|
497
|
+
} @else {
|
|
498
|
+
<button
|
|
499
|
+
#bell
|
|
500
|
+
type="button"
|
|
501
|
+
class="cb-nc__bell"
|
|
502
|
+
[attr.aria-label]="bellLabel()"
|
|
503
|
+
aria-haspopup="dialog"
|
|
504
|
+
[attr.aria-expanded]="open()"
|
|
505
|
+
[attr.aria-controls]="open() ? panelId : null"
|
|
506
|
+
(click)="toggle()"
|
|
507
|
+
>
|
|
508
|
+
<cb-icon name="bell" [size]="20" aria-hidden="true" />
|
|
509
|
+
@if (unread()) {
|
|
510
|
+
<span class="cb-nc__badge" aria-hidden="true">{{ badge() }}</span>
|
|
511
|
+
}
|
|
512
|
+
</button>
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
<div class="cb-nc__sr" aria-live="polite">{{ announcement() }}</div>
|
|
516
|
+
|
|
517
|
+
<ng-template #panelTpl>
|
|
518
|
+
<div
|
|
519
|
+
class="cb-nc__panel"
|
|
520
|
+
[id]="panelId"
|
|
521
|
+
[attr.role]="inline() ? 'region' : 'dialog'"
|
|
522
|
+
[attr.aria-labelledby]="panelId + '-title'"
|
|
523
|
+
[style.width]="inline() ? null : panelWidth()"
|
|
524
|
+
(keydown)="onPanelKeydown($event)"
|
|
525
|
+
(focusin)="focusInside = true"
|
|
526
|
+
(focusout)="onPanelFocusOut($event)"
|
|
527
|
+
>
|
|
528
|
+
<div class="cb-nc__header">
|
|
529
|
+
<span class="cb-nc__title" role="heading" [attr.aria-level]="headingLevel()" [id]="panelId + '-title'" tabindex="-1">
|
|
530
|
+
{{ heading() ?? t().notificationsTitle }}
|
|
531
|
+
</span>
|
|
532
|
+
<button type="button" class="cb-nc__link" [disabled]="!unread()" (click)="markAllRead()">
|
|
533
|
+
<cb-icon name="check-check" [size]="16" aria-hidden="true" />
|
|
534
|
+
{{ t().notificationsMarkAllRead }}
|
|
535
|
+
</button>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
<div class="cb-nc__filter" role="group" [attr.aria-label]="t().notificationsShow">
|
|
539
|
+
<button type="button" class="cb-nc__filter-btn" [attr.aria-pressed]="filter() === 'all'" (click)="filter.set('all')">
|
|
540
|
+
{{ t().notificationsAll }}
|
|
541
|
+
</button>
|
|
542
|
+
<button type="button" class="cb-nc__filter-btn" [attr.aria-pressed]="filter() === 'unread'" (click)="filter.set('unread')">
|
|
543
|
+
{{ t().notificationsUnread }}
|
|
544
|
+
@if (unread()) {
|
|
545
|
+
<span class="cb-nc__count">{{ unread() }}</span>
|
|
546
|
+
}
|
|
547
|
+
</button>
|
|
548
|
+
</div>
|
|
549
|
+
|
|
550
|
+
<div class="cb-nc__body" [style.max-height]="maxHeight()">
|
|
551
|
+
@for (g of groups(); track g.key) {
|
|
552
|
+
@if (groupByDate()) {
|
|
553
|
+
<span class="cb-nc__group" role="heading" [attr.aria-level]="headingLevel() + 1" [id]="panelId + '-' + g.key">{{ groupLabel(g.key) }}</span>
|
|
554
|
+
}
|
|
555
|
+
<ul class="cb-nc__list" [attr.aria-labelledby]="groupByDate() ? panelId + '-' + g.key : panelId + '-title'">
|
|
556
|
+
@for (n of g.items; track n.id) {
|
|
557
|
+
<li class="cb-nc__item" [class.cb-nc__item--unread]="!n.read" [attr.data-id]="n.id">
|
|
558
|
+
<span class="cb-nc__media" aria-hidden="true">
|
|
559
|
+
@if (n.person; as p) {
|
|
560
|
+
<cb-avatar [image]="p.image ?? ''" [label]="initials(p.name)" [size]="36" />
|
|
561
|
+
} @else {
|
|
562
|
+
<span class="cb-nc__icon" [attr.data-severity]="n.severity || 'info'">
|
|
563
|
+
<cb-icon [name]="iconOf(n)" [size]="18" />
|
|
564
|
+
</span>
|
|
565
|
+
}
|
|
566
|
+
</span>
|
|
567
|
+
<div class="cb-nc__content">
|
|
568
|
+
<button type="button" class="cb-nc__main" [attr.aria-describedby]="itemId(n) + '-time'" (click)="select(n)">
|
|
569
|
+
@if (!n.read) {
|
|
570
|
+
<span class="cb-nc__sr">{{ t().notificationsUnreadItem }}: </span>
|
|
571
|
+
}
|
|
572
|
+
<span class="cb-nc__item-title">{{ n.title }}</span>
|
|
573
|
+
@if (n.text) {
|
|
574
|
+
<span class="cb-nc__text">{{ n.text }}</span>
|
|
575
|
+
}
|
|
576
|
+
</button>
|
|
577
|
+
<time class="cb-nc__time" [id]="itemId(n) + '-time'" [attr.datetime]="iso(n.date)" [attr.title]="full(n.date)">{{ rel(n.date) }}</time>
|
|
578
|
+
@if (n.actions?.length) {
|
|
579
|
+
<div class="cb-nc__actions">
|
|
580
|
+
@for (a of n.actions; track a.id) {
|
|
581
|
+
<button type="button" class="cb-nc__action" [class.cb-nc__action--primary]="a.severity === 'primary'" (click)="runAction(n, a)">
|
|
582
|
+
{{ a.label }}
|
|
583
|
+
</button>
|
|
584
|
+
}
|
|
585
|
+
</div>
|
|
586
|
+
}
|
|
587
|
+
</div>
|
|
588
|
+
@if (!n.read) {
|
|
589
|
+
<span class="cb-nc__dot" aria-hidden="true"></span>
|
|
590
|
+
}
|
|
591
|
+
<div class="cb-nc__tools">
|
|
592
|
+
<button
|
|
593
|
+
type="button"
|
|
594
|
+
class="cb-nc__tool"
|
|
595
|
+
[attr.aria-label]="fmt(n.read ? t().notificationsMarkUnread : t().notificationsMarkRead, n.title)"
|
|
596
|
+
[attr.title]="n.read ? t().notificationsMarkUnreadShort : t().notificationsMarkReadShort"
|
|
597
|
+
(click)="setRead(n, !n.read)"
|
|
598
|
+
>
|
|
599
|
+
<cb-icon [name]="n.read ? 'mail' : 'check'" [size]="15" aria-hidden="true" />
|
|
600
|
+
</button>
|
|
601
|
+
@if (removable()) {
|
|
602
|
+
<button type="button" class="cb-nc__tool" [attr.aria-label]="fmt(t().removeItem, n.title)" [attr.title]="t().remove" (click)="remove(n)">
|
|
603
|
+
<cb-icon name="x" [size]="15" aria-hidden="true" />
|
|
604
|
+
</button>
|
|
605
|
+
}
|
|
606
|
+
</div>
|
|
607
|
+
</li>
|
|
608
|
+
}
|
|
609
|
+
</ul>
|
|
610
|
+
} @empty {
|
|
611
|
+
<div class="cb-nc__empty">
|
|
612
|
+
<cb-icon name="bell-off" [size]="28" aria-hidden="true" />
|
|
613
|
+
<p>{{ filter() === 'unread' && notifications().length ? t().notificationsAllRead : (emptyMessage() ?? t().notificationsEmpty) }}</p>
|
|
614
|
+
</div>
|
|
615
|
+
}
|
|
616
|
+
</div>
|
|
617
|
+
|
|
618
|
+
@if (showViewAll()) {
|
|
619
|
+
<div class="cb-nc__footer">
|
|
620
|
+
<button type="button" class="cb-nc__link" (click)="onViewAll()">{{ t().notificationsViewAll }}</button>
|
|
621
|
+
</div>
|
|
622
|
+
}
|
|
623
|
+
</div>
|
|
624
|
+
</ng-template>
|
|
625
|
+
`, styles: [".cb-notification-center{display:inline-block;position:relative;color:var(--cb-color-text);font-family:var(--cb-font-sans)}.cb-notification-center--inline{display:block}.cb-nc__bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:0;border-radius:var(--cb-radius-full, 999px);background:transparent;color:var(--cb-color-text);cursor:pointer}.cb-nc__bell:hover,.cb-nc__bell[aria-expanded=true]{background:var(--cb-color-surface-hover)}.cb-nc__badge{position:absolute;top:.125rem;right:.125rem;min-width:1.125rem;height:1.125rem;padding:0 .25rem;box-sizing:border-box;border:2px solid var(--cb-color-bg, #fff);border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-danger);color:var(--cb-color-danger-contrast, #fff);font-size:.625rem;font-weight:var(--cb-font-weight-semibold, 600);line-height:.875rem;text-align:center}.cb-nc__panel{display:flex;flex-direction:column;box-sizing:border-box;max-width:100%;border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-lg, 8px);background:var(--cb-color-surface-raised, var(--cb-color-surface));color:var(--cb-color-text);font-family:var(--cb-font-sans);font-size:var(--cb-text-sm, .875rem)}.cb-nc-overlay .cb-nc__panel{box-shadow:var(--cb-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .15))}.cb-nc__header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem;padding:.875rem 1rem .5rem}.cb-nc__title{font-size:var(--cb-text-base, 1rem);font-weight:var(--cb-font-weight-semibold, 600)}.cb-nc__title:focus{outline:none}.cb-nc__title:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-nc__link{display:inline-flex;align-items:center;gap:.25rem;padding:.25rem .375rem;border:0;border-radius:var(--cb-radius-sm, 4px);background:transparent;color:var(--cb-color-primary);font:inherit;font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500);cursor:pointer}.cb-nc__link:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-nc__link:disabled{color:var(--cb-color-text-muted);cursor:default}.cb-nc__filter{display:flex;gap:.25rem;padding:0 1rem .5rem;border-bottom:1px solid var(--cb-color-border)}.cb-nc__filter-btn{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .625rem;border:0;border-radius:var(--cb-radius-full, 999px);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500);cursor:pointer}.cb-nc__filter-btn:hover{color:var(--cb-color-text)}.cb-nc__filter-btn[aria-pressed=true]{background:var(--cb-color-surface-hover);color:var(--cb-color-text)}.cb-nc__count{min-width:1.125rem;padding:0 .3125rem;box-sizing:border-box;border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-primary);color:var(--cb-color-primary-contrast, #fff);font-size:.625rem;line-height:1.125rem;text-align:center}.cb-nc__body{overflow-y:auto;overscroll-behavior:contain}.cb-nc__group{display:block;padding:.75rem 1rem .25rem;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-semibold, 600);letter-spacing:.02em;text-transform:uppercase}.cb-nc__list{margin:0;padding:0;list-style:none}.cb-nc__item{display:flex;gap:.75rem;padding:.75rem 1rem}.cb-nc__item+.cb-nc__item{border-top:1px solid var(--cb-color-border)}.cb-nc__item--unread{background:color-mix(in srgb,var(--cb-color-primary) 6%,transparent)}.cb-nc__item:hover{background:color-mix(in srgb,var(--cb-color-text) 5%,transparent)}.cb-nc__media{flex:none}.cb-nc__icon{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:var(--cb-radius-full, 999px);--_c: var(--cb-color-info);background:color-mix(in srgb,var(--_c) 14%,transparent);color:var(--_c)}.cb-nc__icon[data-severity=success]{--_c: var(--cb-color-success)}.cb-nc__icon[data-severity=warning]{--_c: var(--cb-color-warning)}.cb-nc__icon[data-severity=danger]{--_c: var(--cb-color-danger)}.cb-nc__content{display:flex;flex:1;flex-direction:column;gap:.125rem;min-width:0}.cb-nc__main{display:flex;flex-direction:column;gap:.125rem;padding:0;border:0;border-radius:var(--cb-radius-sm, 4px);background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.cb-nc__item{position:relative}.cb-nc__main:after{content:\"\";position:absolute;inset:0}.cb-nc__tools,.cb-nc__actions,.cb-nc__time{position:relative;z-index:1}.cb-nc__item-title{font-weight:var(--cb-font-weight-medium, 500);overflow-wrap:anywhere}.cb-nc__item--unread .cb-nc__item-title{font-weight:var(--cb-font-weight-semibold, 600)}.cb-nc__text{display:-webkit-box;overflow:hidden;color:var(--cb-color-text-muted);-webkit-box-orient:vertical;-webkit-line-clamp:2}.cb-nc__time{align-self:flex-start;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs, .75rem)}.cb-nc__actions{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.375rem}.cb-nc__action{min-height:1.75rem;padding:0 .75rem;border:1px solid var(--cb-color-border-strong, var(--cb-color-border));border-radius:var(--cb-radius-md, 6px);background:var(--cb-color-surface-raised, transparent);color:var(--cb-color-text);font:inherit;font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500);cursor:pointer}.cb-nc__action:hover{background:var(--cb-color-surface-hover)}.cb-nc__action--primary{border-color:var(--cb-color-primary);background:var(--cb-color-primary);color:var(--cb-color-primary-contrast, #fff)}.cb-nc__action--primary:hover{background:var(--cb-color-primary-700, var(--cb-color-primary))}.cb-nc__tools{position:absolute;top:.5rem;right:.75rem;display:flex;gap:.125rem;padding:.125rem;border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-surface-raised, var(--cb-color-surface));box-shadow:var(--cb-shadow-sm, 0 1px 2px rgba(0, 0, 0, .08));opacity:0}.cb-nc__dot{flex:none;width:.5rem;height:.5rem;margin:.375rem 0 0;border-radius:var(--cb-radius-full, 999px);background:var(--cb-color-primary)}.cb-nc__tool{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border:0;border-radius:var(--cb-radius-full, 999px);background:transparent;color:var(--cb-color-text-muted);cursor:pointer}.cb-nc__item:hover .cb-nc__tools,.cb-nc__item:focus-within .cb-nc__tools{opacity:1}@media(hover:none){.cb-nc__tools{position:static;align-self:flex-start;border:0;box-shadow:none;background:transparent;opacity:1}}.cb-nc__tool:hover{background:var(--cb-color-surface-active, var(--cb-color-border));color:var(--cb-color-text)}.cb-nc__empty{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding:2rem 1rem;color:var(--cb-color-text-muted);text-align:center}.cb-nc__empty p{margin:0}.cb-nc__footer{display:flex;justify-content:center;padding:.5rem;border-top:1px solid var(--cb-color-border)}.cb-nc__bell:focus-visible,.cb-nc__link:focus-visible,.cb-nc__filter-btn:focus-visible,.cb-nc__action:focus-visible,.cb-nc__tool:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:1px}.cb-nc__main:focus-visible{outline:none}.cb-nc__item:has(.cb-nc__main:focus-visible){outline:2px solid var(--cb-color-focus-ring);outline-offset:-2px}.cb-nc__sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}\n"] }]
|
|
626
|
+
}], ctorParameters: () => [], propDecorators: { notifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "notifications", required: false }] }, { type: i0.Output, args: ["notificationsChange"] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }, { type: i0.Output, args: ["filterChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }], groupByDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupByDate", required: false }] }], removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], closeOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnSelect", required: false }] }], announceNew: [{ type: i0.Input, args: [{ isSignal: true, alias: "announceNew", required: false }] }], showViewAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "showViewAll", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], headingLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingLevel", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], readChange: [{ type: i0.Output, args: ["readChange"] }], markAll: [{ type: i0.Output, args: ["markAll"] }], itemRemove: [{ type: i0.Output, args: ["itemRemove"] }], viewAll: [{ type: i0.Output, args: ["viewAll"] }], panelTpl: [{ type: i0.ViewChild, args: ['panelTpl', { isSignal: true }] }], bell: [{ type: i0.ViewChild, args: ['bell', { isSignal: true }] }] } });
|
|
627
|
+
|
|
628
|
+
/*
|
|
629
|
+
* Public API Surface de @caribeng/ui/notification-center
|
|
630
|
+
*/
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Generated bundle index. Do not edit.
|
|
634
|
+
*/
|
|
635
|
+
|
|
636
|
+
export { CbNotificationCenter };
|