@muxima-ui/core 1.1.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.
@@ -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":"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"}
@@ -0,0 +1,333 @@
1
+ import * as i0 from '@angular/core';
2
+ import { model, input, inject, DOCUMENT, DestroyRef, ViewEncapsulation, ChangeDetectionStrategy, Component, ElementRef, Directive, booleanAttribute, computed } from '@angular/core';
3
+ import { mxUniqueId } from '@muxima-ui/core/form-field';
4
+
5
+ /**
6
+ * Navegação lateral que recolhe para só ícones. O conteúdo fica dentro de um `<nav>`;
7
+ * recolhida, os nomes continuam lá para o leitor de ecrã e aparecem numa dica ao passar
8
+ * o rato ou com o foco.
9
+ *
10
+ * ```html
11
+ * <mx-sidebar [(collapsed)]="recolhida" aria-label="Principal">
12
+ * <div mxSidebarHeader>Kianda</div>
13
+ * <mx-sidebar-group label="Gestão">
14
+ * <li><a mxSidebarItem routerLink="/facturas" routerLinkActive ariaCurrentWhenActive="page">
15
+ * <svg mxSidebarIcon>...</svg><span mxSidebarLabel>Facturas</span>
16
+ * </a></li>
17
+ * </mx-sidebar-group>
18
+ * <div mxSidebarFooter>...</div>
19
+ * </mx-sidebar>
20
+ * <button mxSidebarToggle [sidebar]="menu">...</button>
21
+ * ```
22
+ *
23
+ * O item da página actual leva aria-current="page" (o routerLinkActive faz isso com
24
+ * ariaCurrentWhenActive).
25
+ */
26
+ class MxSidebar {
27
+ collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
28
+ ariaLabel = input('Principal', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
29
+ /** `default` com fundo de superfície; `subtle` com o fundo do papel. */
30
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
31
+ id = input(mxUniqueId('mx-sidebar'), ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
32
+ doc = inject(DOCUMENT);
33
+ /** A dica vive no body, para não ser cortada nem deslocada por contentores da página. */
34
+ tipEl;
35
+ constructor() {
36
+ inject(DestroyRef).onDestroy(() => this.tipEl?.remove());
37
+ }
38
+ toggle() {
39
+ this.collapsed.update((c) => !c);
40
+ this.hideTip();
41
+ }
42
+ /** Mostra a dica de um item (só com a barra recolhida). */
43
+ showTip(el) {
44
+ if (!this.collapsed())
45
+ return;
46
+ const text = el.querySelector('.mx-sidebar-label')?.textContent?.trim() ||
47
+ el.getAttribute('aria-label') ||
48
+ '';
49
+ if (!text)
50
+ return;
51
+ const r = el.getBoundingClientRect();
52
+ if (!this.tipEl) {
53
+ this.tipEl = this.doc.createElement('div');
54
+ this.tipEl.className = 'mx-tooltip mx-sidebar-tip';
55
+ this.tipEl.setAttribute('aria-hidden', 'true');
56
+ }
57
+ this.tipEl.textContent = text;
58
+ this.tipEl.style.top = `${r.top + r.height / 2}px`;
59
+ this.tipEl.style.left = `${r.right + 8}px`;
60
+ if (!this.tipEl.isConnected)
61
+ this.doc.body.appendChild(this.tipEl);
62
+ }
63
+ hideTip() {
64
+ this.tipEl?.remove();
65
+ }
66
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
67
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.25", type: MxSidebar, isStandalone: true, selector: "mx-sidebar", inputs: { collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "id": "id()", "attr.data-collapsed": "collapsed() ? \"\" : null", "attr.data-variant": "variant() === \"default\" ? null : variant()", "attr.aria-label": "null" }, classAttribute: "mx-sidebar" }, exportAs: ["mxSidebar"], ngImport: i0, template: `
68
+ <ng-content select="[mxSidebarHeader]" />
69
+ <nav class="mx-sidebar-nav" [attr.aria-label]="ariaLabel()">
70
+ <ng-content />
71
+ </nav>
72
+ <ng-content select="[mxSidebarFooter]" />
73
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
74
+ }
75
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebar, decorators: [{
76
+ type: Component,
77
+ args: [{
78
+ selector: 'mx-sidebar',
79
+ exportAs: 'mxSidebar',
80
+ changeDetection: ChangeDetectionStrategy.OnPush,
81
+ encapsulation: ViewEncapsulation.None,
82
+ host: {
83
+ class: 'mx-sidebar',
84
+ '[id]': 'id()',
85
+ '[attr.data-collapsed]': 'collapsed() ? "" : null',
86
+ '[attr.data-variant]': 'variant() === "default" ? null : variant()',
87
+ '[attr.aria-label]': 'null',
88
+ },
89
+ template: `
90
+ <ng-content select="[mxSidebarHeader]" />
91
+ <nav class="mx-sidebar-nav" [attr.aria-label]="ariaLabel()">
92
+ <ng-content />
93
+ </nav>
94
+ <ng-content select="[mxSidebarFooter]" />
95
+ `,
96
+ }]
97
+ }], ctorParameters: () => [], propDecorators: { collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
98
+ /** Link ou botão da barra. Põe o texto em `mxSidebarLabel` e o ícone em `mxSidebarIcon`. */
99
+ class MxSidebarItem {
100
+ sidebar = inject(MxSidebar, { optional: true });
101
+ el = inject(ElementRef).nativeElement;
102
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
103
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxSidebarItem, isStandalone: true, selector: "a[mxSidebarItem], button[mxSidebarItem]", host: { listeners: { "mouseenter": "sidebar?.showTip(el)", "focus": "sidebar?.showTip(el)", "mouseleave": "sidebar?.hideTip()", "blur": "sidebar?.hideTip()" }, classAttribute: "mx-sidebar-item" }, exportAs: ["mxSidebarItem"], ngImport: i0 });
104
+ }
105
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarItem, decorators: [{
106
+ type: Directive,
107
+ args: [{
108
+ selector: 'a[mxSidebarItem], button[mxSidebarItem]',
109
+ exportAs: 'mxSidebarItem',
110
+ host: {
111
+ class: 'mx-sidebar-item',
112
+ '(mouseenter)': 'sidebar?.showTip(el)',
113
+ '(focus)': 'sidebar?.showTip(el)',
114
+ '(mouseleave)': 'sidebar?.hideTip()',
115
+ '(blur)': 'sidebar?.hideTip()',
116
+ },
117
+ }]
118
+ }] });
119
+ class MxSidebarLabel {
120
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
121
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxSidebarLabel, isStandalone: true, selector: "[mxSidebarLabel]", host: { classAttribute: "mx-sidebar-label" }, ngImport: i0 });
122
+ }
123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarLabel, decorators: [{
124
+ type: Directive,
125
+ args: [{ selector: '[mxSidebarLabel]', host: { class: 'mx-sidebar-label' } }]
126
+ }] });
127
+ class MxSidebarIcon {
128
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive });
129
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxSidebarIcon, isStandalone: true, selector: "[mxSidebarIcon]", host: { attributes: { "aria-hidden": "true" }, classAttribute: "mx-sidebar-icon" }, ngImport: i0 });
130
+ }
131
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarIcon, decorators: [{
132
+ type: Directive,
133
+ args: [{
134
+ selector: '[mxSidebarIcon]',
135
+ host: { class: 'mx-sidebar-icon', 'aria-hidden': 'true' },
136
+ }]
137
+ }] });
138
+ /** Contagem ou estado à direita do item; recolhida, passa a ponto. */
139
+ class MxSidebarBadge {
140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarBadge, deps: [], target: i0.ɵɵFactoryTarget.Directive });
141
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxSidebarBadge, isStandalone: true, selector: "[mxSidebarBadge]", host: { classAttribute: "mx-sidebar-badge" }, ngImport: i0 });
142
+ }
143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarBadge, decorators: [{
144
+ type: Directive,
145
+ args: [{ selector: '[mxSidebarBadge]', host: { class: 'mx-sidebar-badge' } }]
146
+ }] });
147
+ class MxSidebarHeader {
148
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive });
149
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxSidebarHeader, isStandalone: true, selector: "[mxSidebarHeader]", host: { classAttribute: "mx-sidebar-header" }, ngImport: i0 });
150
+ }
151
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarHeader, decorators: [{
152
+ type: Directive,
153
+ args: [{ selector: '[mxSidebarHeader]', host: { class: 'mx-sidebar-header' } }]
154
+ }] });
155
+ class MxSidebarFooter {
156
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarFooter, deps: [], target: i0.ɵɵFactoryTarget.Directive });
157
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxSidebarFooter, isStandalone: true, selector: "[mxSidebarFooter]", host: { classAttribute: "mx-sidebar-footer" }, ngImport: i0 });
158
+ }
159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarFooter, decorators: [{
160
+ type: Directive,
161
+ args: [{ selector: '[mxSidebarFooter]', host: { class: 'mx-sidebar-footer' } }]
162
+ }] });
163
+ /**
164
+ * Grupo de itens com título. O título dá nome à lista (aria-labelledby); recolhida,
165
+ * o título fica escondido só visualmente. Os itens vão em `<li>`.
166
+ */
167
+ class MxSidebarGroup {
168
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
169
+ labelId = mxUniqueId('mx-sidebar-group');
170
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
171
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: MxSidebarGroup, isStandalone: true, selector: "mx-sidebar-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "mx-sidebar-group" }, ngImport: i0, template: `
172
+ @if (label()) {
173
+ <p class="mx-sidebar-group-label" [id]="labelId">{{ label() }}</p>
174
+ }
175
+ <ul class="mx-sidebar-list" [attr.aria-labelledby]="label() ? labelId : null">
176
+ <ng-content />
177
+ </ul>
178
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
179
+ }
180
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarGroup, decorators: [{
181
+ type: Component,
182
+ args: [{
183
+ selector: 'mx-sidebar-group',
184
+ changeDetection: ChangeDetectionStrategy.OnPush,
185
+ encapsulation: ViewEncapsulation.None,
186
+ host: { class: 'mx-sidebar-group' },
187
+ template: `
188
+ @if (label()) {
189
+ <p class="mx-sidebar-group-label" [id]="labelId">{{ label() }}</p>
190
+ }
191
+ <ul class="mx-sidebar-list" [attr.aria-labelledby]="label() ? labelId : null">
192
+ <ng-content />
193
+ </ul>
194
+ `,
195
+ }]
196
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
197
+ /**
198
+ * Secção que abre e fecha (botão com aria-expanded). Com a barra recolhida, carregar na
199
+ * secção expande a barra e abre a secção.
200
+ *
201
+ * ```html
202
+ * <li><mx-sidebar-section label="Relatórios" [(open)]="aberta">
203
+ * <svg mxSidebarIcon>...</svg>
204
+ * <li><a mxSidebarItem routerLink="/vendas"><span mxSidebarLabel>Vendas</span></a></li>
205
+ * </mx-sidebar-section></li>
206
+ * ```
207
+ */
208
+ class MxSidebarSection {
209
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
210
+ open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
211
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
212
+ sidebar = inject(MxSidebar, { optional: true });
213
+ listId = mxUniqueId('mx-sidebar-section');
214
+ /** Recolhida, a secção não mostra os filhos. */
215
+ isOpen = computed(() => this.open() && !this.sidebar?.collapsed(), ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
216
+ toggle() {
217
+ if (this.sidebar?.collapsed()) {
218
+ this.sidebar.collapsed.set(false);
219
+ this.sidebar.hideTip();
220
+ this.open.set(true);
221
+ return;
222
+ }
223
+ this.open.update((o) => !o);
224
+ }
225
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarSection, deps: [], target: i0.ɵɵFactoryTarget.Component });
226
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.25", type: MxSidebarSection, isStandalone: true, selector: "mx-sidebar-section", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "attr.data-open": "isOpen() ? \"\" : null" }, classAttribute: "mx-sidebar-section" }, ngImport: i0, template: `
227
+ <button
228
+ type="button"
229
+ mxSidebarItem
230
+ class="mx-sidebar-item mx-sidebar-section-trigger"
231
+ [attr.aria-expanded]="isOpen()"
232
+ [attr.aria-controls]="listId"
233
+ (click)="toggle()"
234
+ >
235
+ <ng-content select="[mxSidebarIcon]" />
236
+ <span class="mx-sidebar-label">{{ label() }}</span>
237
+ <svg class="mx-sidebar-chevron" viewBox="0 0 16 16" aria-hidden="true">
238
+ <path
239
+ d="M6 4l4 4-4 4"
240
+ fill="none"
241
+ stroke="currentColor"
242
+ stroke-width="1.5"
243
+ stroke-linecap="round"
244
+ stroke-linejoin="round"
245
+ />
246
+ </svg>
247
+ </button>
248
+ <ul class="mx-sidebar-list mx-sidebar-sublist" [id]="listId" [hidden]="!isOpen()">
249
+ <ng-content />
250
+ </ul>
251
+ `, isInline: true, dependencies: [{ kind: "directive", type: MxSidebarItem, selector: "a[mxSidebarItem], button[mxSidebarItem]", exportAs: ["mxSidebarItem"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
252
+ }
253
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarSection, decorators: [{
254
+ type: Component,
255
+ args: [{
256
+ selector: 'mx-sidebar-section',
257
+ changeDetection: ChangeDetectionStrategy.OnPush,
258
+ encapsulation: ViewEncapsulation.None,
259
+ host: { class: 'mx-sidebar-section', '[attr.data-open]': 'isOpen() ? "" : null' },
260
+ template: `
261
+ <button
262
+ type="button"
263
+ mxSidebarItem
264
+ class="mx-sidebar-item mx-sidebar-section-trigger"
265
+ [attr.aria-expanded]="isOpen()"
266
+ [attr.aria-controls]="listId"
267
+ (click)="toggle()"
268
+ >
269
+ <ng-content select="[mxSidebarIcon]" />
270
+ <span class="mx-sidebar-label">{{ label() }}</span>
271
+ <svg class="mx-sidebar-chevron" viewBox="0 0 16 16" aria-hidden="true">
272
+ <path
273
+ d="M6 4l4 4-4 4"
274
+ fill="none"
275
+ stroke="currentColor"
276
+ stroke-width="1.5"
277
+ stroke-linecap="round"
278
+ stroke-linejoin="round"
279
+ />
280
+ </svg>
281
+ </button>
282
+ <ul class="mx-sidebar-list mx-sidebar-sublist" [id]="listId" [hidden]="!isOpen()">
283
+ <ng-content />
284
+ </ul>
285
+ `,
286
+ imports: [MxSidebarItem],
287
+ }]
288
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
289
+ /**
290
+ * Botão que recolhe e expande a barra. Tem aria-expanded e aria-controls; o nome muda
291
+ * entre "Recolher menu" e "Expandir menu" (ou os textos que passares).
292
+ */
293
+ class MxSidebarToggle {
294
+ sidebar = input.required(...(ngDevMode ? [{ debugName: "sidebar" }] : /* istanbul ignore next */ []));
295
+ collapseLabel = input('Recolher menu', ...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
296
+ expandLabel = input('Expandir menu', ...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
297
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
298
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: MxSidebarToggle, isStandalone: true, selector: "button[mxSidebarToggle]", inputs: { sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, listeners: { "click": "sidebar().toggle()" }, properties: { "attr.aria-expanded": "!sidebar().collapsed()", "attr.aria-controls": "sidebar().id()", "attr.aria-label": "sidebar().collapsed() ? expandLabel() : collapseLabel()" }, classAttribute: "mx-sidebar-toggle" }, exportAs: ["mxSidebarToggle"], ngImport: i0 });
299
+ }
300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxSidebarToggle, decorators: [{
301
+ type: Directive,
302
+ args: [{
303
+ selector: 'button[mxSidebarToggle]',
304
+ exportAs: 'mxSidebarToggle',
305
+ host: {
306
+ class: 'mx-sidebar-toggle',
307
+ type: 'button',
308
+ '[attr.aria-expanded]': '!sidebar().collapsed()',
309
+ '[attr.aria-controls]': 'sidebar().id()',
310
+ '[attr.aria-label]': 'sidebar().collapsed() ? expandLabel() : collapseLabel()',
311
+ '(click)': 'sidebar().toggle()',
312
+ },
313
+ }]
314
+ }], propDecorators: { sidebar: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebar", required: true }] }], collapseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseLabel", required: false }] }], expandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandLabel", required: false }] }] } });
315
+ const MX_SIDEBAR = [
316
+ MxSidebar,
317
+ MxSidebarItem,
318
+ MxSidebarLabel,
319
+ MxSidebarIcon,
320
+ MxSidebarBadge,
321
+ MxSidebarHeader,
322
+ MxSidebarFooter,
323
+ MxSidebarGroup,
324
+ MxSidebarSection,
325
+ MxSidebarToggle,
326
+ ];
327
+
328
+ /**
329
+ * Generated bundle index. Do not edit.
330
+ */
331
+
332
+ export { MX_SIDEBAR, MxSidebar, MxSidebarBadge, MxSidebarFooter, MxSidebarGroup, MxSidebarHeader, MxSidebarIcon, MxSidebarItem, MxSidebarLabel, MxSidebarSection, MxSidebarToggle };
333
+ //# sourceMappingURL=muxima-ui-core-sidebar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxima-ui-core-sidebar.mjs","sources":["../../../projects/core/sidebar/sidebar.ts","../../../projects/core/sidebar/muxima-ui-core-sidebar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DOCUMENT,\n DestroyRef,\n Directive,\n ElementRef,\n ViewEncapsulation,\n booleanAttribute,\n computed,\n inject,\n input,\n model,\n} from '@angular/core';\nimport { mxUniqueId } from '@muxima-ui/core/form-field';\n\n/**\n * Navegação lateral que recolhe para só ícones. O conteúdo fica dentro de um `<nav>`;\n * recolhida, os nomes continuam lá para o leitor de ecrã e aparecem numa dica ao passar\n * o rato ou com o foco.\n *\n * ```html\n * <mx-sidebar [(collapsed)]=\"recolhida\" aria-label=\"Principal\">\n * <div mxSidebarHeader>Kianda</div>\n * <mx-sidebar-group label=\"Gestão\">\n * <li><a mxSidebarItem routerLink=\"/facturas\" routerLinkActive ariaCurrentWhenActive=\"page\">\n * <svg mxSidebarIcon>...</svg><span mxSidebarLabel>Facturas</span>\n * </a></li>\n * </mx-sidebar-group>\n * <div mxSidebarFooter>...</div>\n * </mx-sidebar>\n * <button mxSidebarToggle [sidebar]=\"menu\">...</button>\n * ```\n *\n * O item da página actual leva aria-current=\"page\" (o routerLinkActive faz isso com\n * ariaCurrentWhenActive).\n */\n@Component({\n selector: 'mx-sidebar',\n exportAs: 'mxSidebar',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'mx-sidebar',\n '[id]': 'id()',\n '[attr.data-collapsed]': 'collapsed() ? \"\" : null',\n '[attr.data-variant]': 'variant() === \"default\" ? null : variant()',\n '[attr.aria-label]': 'null',\n },\n template: `\n <ng-content select=\"[mxSidebarHeader]\" />\n <nav class=\"mx-sidebar-nav\" [attr.aria-label]=\"ariaLabel()\">\n <ng-content />\n </nav>\n <ng-content select=\"[mxSidebarFooter]\" />\n `,\n})\nexport class MxSidebar {\n readonly collapsed = model(false);\n readonly ariaLabel = input('Principal', { alias: 'aria-label' });\n /** `default` com fundo de superfície; `subtle` com o fundo do papel. */\n readonly variant = input<'default' | 'subtle'>('default');\n readonly id = input(mxUniqueId('mx-sidebar'));\n\n private readonly doc = inject(DOCUMENT);\n /** A dica vive no body, para não ser cortada nem deslocada por contentores da página. */\n private tipEl?: HTMLElement;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.tipEl?.remove());\n }\n\n toggle(): void {\n this.collapsed.update((c) => !c);\n this.hideTip();\n }\n\n /** Mostra a dica de um item (só com a barra recolhida). */\n showTip(el: HTMLElement): void {\n if (!this.collapsed()) return;\n const text =\n el.querySelector('.mx-sidebar-label')?.textContent?.trim() ||\n el.getAttribute('aria-label') ||\n '';\n if (!text) return;\n const r = el.getBoundingClientRect();\n if (!this.tipEl) {\n this.tipEl = this.doc.createElement('div');\n this.tipEl.className = 'mx-tooltip mx-sidebar-tip';\n this.tipEl.setAttribute('aria-hidden', 'true');\n }\n this.tipEl.textContent = text;\n this.tipEl.style.top = `${r.top + r.height / 2}px`;\n this.tipEl.style.left = `${r.right + 8}px`;\n if (!this.tipEl.isConnected) this.doc.body.appendChild(this.tipEl);\n }\n hideTip(): void {\n this.tipEl?.remove();\n }\n}\n\n/** Link ou botão da barra. Põe o texto em `mxSidebarLabel` e o ícone em `mxSidebarIcon`. */\n@Directive({\n selector: 'a[mxSidebarItem], button[mxSidebarItem]',\n exportAs: 'mxSidebarItem',\n host: {\n class: 'mx-sidebar-item',\n '(mouseenter)': 'sidebar?.showTip(el)',\n '(focus)': 'sidebar?.showTip(el)',\n '(mouseleave)': 'sidebar?.hideTip()',\n '(blur)': 'sidebar?.hideTip()',\n },\n})\nexport class MxSidebarItem {\n protected readonly sidebar = inject(MxSidebar, { optional: true });\n protected readonly el = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n}\n\n@Directive({ selector: '[mxSidebarLabel]', host: { class: 'mx-sidebar-label' } })\nexport class MxSidebarLabel {}\n\n@Directive({\n selector: '[mxSidebarIcon]',\n host: { class: 'mx-sidebar-icon', 'aria-hidden': 'true' },\n})\nexport class MxSidebarIcon {}\n\n/** Contagem ou estado à direita do item; recolhida, passa a ponto. */\n@Directive({ selector: '[mxSidebarBadge]', host: { class: 'mx-sidebar-badge' } })\nexport class MxSidebarBadge {}\n\n@Directive({ selector: '[mxSidebarHeader]', host: { class: 'mx-sidebar-header' } })\nexport class MxSidebarHeader {}\n\n@Directive({ selector: '[mxSidebarFooter]', host: { class: 'mx-sidebar-footer' } })\nexport class MxSidebarFooter {}\n\n/**\n * Grupo de itens com título. O título dá nome à lista (aria-labelledby); recolhida,\n * o título fica escondido só visualmente. Os itens vão em `<li>`.\n */\n@Component({\n selector: 'mx-sidebar-group',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'mx-sidebar-group' },\n template: `\n @if (label()) {\n <p class=\"mx-sidebar-group-label\" [id]=\"labelId\">{{ label() }}</p>\n }\n <ul class=\"mx-sidebar-list\" [attr.aria-labelledby]=\"label() ? labelId : null\">\n <ng-content />\n </ul>\n `,\n})\nexport class MxSidebarGroup {\n readonly label = input('');\n protected readonly labelId = mxUniqueId('mx-sidebar-group');\n}\n\n/**\n * Secção que abre e fecha (botão com aria-expanded). Com a barra recolhida, carregar na\n * secção expande a barra e abre a secção.\n *\n * ```html\n * <li><mx-sidebar-section label=\"Relatórios\" [(open)]=\"aberta\">\n * <svg mxSidebarIcon>...</svg>\n * <li><a mxSidebarItem routerLink=\"/vendas\"><span mxSidebarLabel>Vendas</span></a></li>\n * </mx-sidebar-section></li>\n * ```\n */\n@Component({\n selector: 'mx-sidebar-section',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'mx-sidebar-section', '[attr.data-open]': 'isOpen() ? \"\" : null' },\n template: `\n <button\n type=\"button\"\n mxSidebarItem\n class=\"mx-sidebar-item mx-sidebar-section-trigger\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"listId\"\n (click)=\"toggle()\"\n >\n <ng-content select=\"[mxSidebarIcon]\" />\n <span class=\"mx-sidebar-label\">{{ label() }}</span>\n <svg class=\"mx-sidebar-chevron\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M6 4l4 4-4 4\"\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 <ul class=\"mx-sidebar-list mx-sidebar-sublist\" [id]=\"listId\" [hidden]=\"!isOpen()\">\n <ng-content />\n </ul>\n `,\n imports: [MxSidebarItem],\n})\nexport class MxSidebarSection {\n readonly label = input.required<string>();\n readonly open = model(false);\n readonly disabled = input(false, { transform: booleanAttribute });\n private readonly sidebar = inject(MxSidebar, { optional: true });\n protected readonly listId = mxUniqueId('mx-sidebar-section');\n /** Recolhida, a secção não mostra os filhos. */\n protected readonly isOpen = computed(() => this.open() && !this.sidebar?.collapsed());\n\n protected toggle(): void {\n if (this.sidebar?.collapsed()) {\n this.sidebar.collapsed.set(false);\n this.sidebar.hideTip();\n this.open.set(true);\n return;\n }\n this.open.update((o) => !o);\n }\n}\n\n/**\n * Botão que recolhe e expande a barra. Tem aria-expanded e aria-controls; o nome muda\n * entre \"Recolher menu\" e \"Expandir menu\" (ou os textos que passares).\n */\n@Directive({\n selector: 'button[mxSidebarToggle]',\n exportAs: 'mxSidebarToggle',\n host: {\n class: 'mx-sidebar-toggle',\n type: 'button',\n '[attr.aria-expanded]': '!sidebar().collapsed()',\n '[attr.aria-controls]': 'sidebar().id()',\n '[attr.aria-label]': 'sidebar().collapsed() ? expandLabel() : collapseLabel()',\n '(click)': 'sidebar().toggle()',\n },\n})\nexport class MxSidebarToggle {\n readonly sidebar = input.required<MxSidebar>();\n readonly collapseLabel = input('Recolher menu');\n readonly expandLabel = input('Expandir menu');\n}\n\nexport const MX_SIDEBAR = [\n MxSidebar,\n MxSidebarItem,\n MxSidebarLabel,\n MxSidebarIcon,\n MxSidebarBadge,\n MxSidebarHeader,\n MxSidebarFooter,\n MxSidebarGroup,\n MxSidebarSection,\n MxSidebarToggle,\n] as const;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, Directive, booleanAttribute } from '@angular/core';
3
+
4
+ /**
5
+ * Acontecimentos por ordem, sobre uma lista ordenada nativa: o leitor de ecrã anuncia
6
+ * "lista, 4 itens" e a posição de cada um.
7
+ *
8
+ * ```html
9
+ * <ol mxTimeline>
10
+ * <li mxTimelineItem variant="success">
11
+ * <time mxTimelineTime datetime="2026-10-27T09:40">27 out, 09:40</time>
12
+ * <p mxTimelineTitle>Factura paga</p>
13
+ * <p mxTimelineDescription>Banco Mutamba pagou FT 2026/0196.</p>
14
+ * </li>
15
+ * </ol>
16
+ * ```
17
+ */
18
+ class MxTimeline {
19
+ orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
20
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
21
+ /** `alternate` põe os itens alternadamente dos dois lados da linha (só vertical, ecrãs largos). */
22
+ align = input('start', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
23
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimeline, deps: [], target: i0.ɵɵFactoryTarget.Directive });
24
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: MxTimeline, isStandalone: true, selector: "ol[mxTimeline], ul[mxTimeline]", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-orientation": "orientation() === \"vertical\" ? null : orientation()", "attr.data-size": "size() === \"md\" ? null : size()", "attr.data-align": "align() === \"start\" ? null : align()", "attr.tabindex": "orientation() === \"horizontal\" ? 0 : null" }, classAttribute: "mx-timeline" }, exportAs: ["mxTimeline"], ngImport: i0 });
25
+ }
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimeline, decorators: [{
27
+ type: Directive,
28
+ args: [{
29
+ selector: 'ol[mxTimeline], ul[mxTimeline]',
30
+ exportAs: 'mxTimeline',
31
+ host: {
32
+ class: 'mx-timeline',
33
+ '[attr.data-orientation]': 'orientation() === "vertical" ? null : orientation()',
34
+ '[attr.data-size]': 'size() === "md" ? null : size()',
35
+ '[attr.data-align]': 'align() === "start" ? null : align()',
36
+ // na horizontal pode haver scroll: o teclado tem de lá chegar
37
+ '[attr.tabindex]': 'orientation() === "horizontal" ? 0 : null',
38
+ },
39
+ }]
40
+ }], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }] } });
41
+ /**
42
+ * Um acontecimento. O marcador fica na linha; com `pending` aparece tracejado
43
+ * (passo ainda por acontecer). Diz isso também no texto, para o leitor de ecrã.
44
+ */
45
+ class MxTimelineItem {
46
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
47
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
48
+ /** Marcador maior, com espaço para um ícone (mxTimelineIcon). */
49
+ icon = input(false, { ...(ngDevMode ? { debugName: "icon" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
50
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
51
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: MxTimelineItem, isStandalone: true, selector: "li[mxTimelineItem]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, pending: { classPropertyName: "pending", publicName: "pending", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variant": "variant() === \"default\" ? null : variant()", "attr.data-pending": "pending() ? \"\" : null", "attr.data-has-icon": "icon() ? \"\" : null" }, classAttribute: "mx-timeline-item" }, exportAs: ["mxTimelineItem"], ngImport: i0 });
52
+ }
53
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineItem, decorators: [{
54
+ type: Directive,
55
+ args: [{
56
+ selector: 'li[mxTimelineItem]',
57
+ exportAs: 'mxTimelineItem',
58
+ host: {
59
+ class: 'mx-timeline-item',
60
+ '[attr.data-variant]': 'variant() === "default" ? null : variant()',
61
+ '[attr.data-pending]': 'pending() ? "" : null',
62
+ '[attr.data-has-icon]': 'icon() ? "" : null',
63
+ },
64
+ }]
65
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }] } });
66
+ /** Ícone dentro do marcador (svg decorativo). Usa com `icon` no item. */
67
+ class MxTimelineIcon {
68
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive });
69
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineIcon, isStandalone: true, selector: "[mxTimelineIcon]", host: { attributes: { "aria-hidden": "true" }, classAttribute: "mx-timeline-icon" }, ngImport: i0 });
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineIcon, decorators: [{
72
+ type: Directive,
73
+ args: [{
74
+ selector: '[mxTimelineIcon]',
75
+ host: { class: 'mx-timeline-icon', 'aria-hidden': 'true' },
76
+ }]
77
+ }] });
78
+ /** Data ou hora do acontecimento. Usa um `<time datetime>`. */
79
+ class MxTimelineTime {
80
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTime, deps: [], target: i0.ɵɵFactoryTarget.Directive });
81
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineTime, isStandalone: true, selector: "[mxTimelineTime]", host: { classAttribute: "mx-timeline-time" }, ngImport: i0 });
82
+ }
83
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTime, decorators: [{
84
+ type: Directive,
85
+ args: [{ selector: '[mxTimelineTime]', host: { class: 'mx-timeline-time' } }]
86
+ }] });
87
+ class MxTimelineTitle {
88
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTitle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
89
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineTitle, isStandalone: true, selector: "[mxTimelineTitle]", host: { classAttribute: "mx-timeline-title" }, ngImport: i0 });
90
+ }
91
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTitle, decorators: [{
92
+ type: Directive,
93
+ args: [{ selector: '[mxTimelineTitle]', host: { class: 'mx-timeline-title' } }]
94
+ }] });
95
+ class MxTimelineDescription {
96
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive });
97
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineDescription, isStandalone: true, selector: "[mxTimelineDescription]", host: { classAttribute: "mx-timeline-description" }, ngImport: i0 });
98
+ }
99
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineDescription, decorators: [{
100
+ type: Directive,
101
+ args: [{ selector: '[mxTimelineDescription]', host: { class: 'mx-timeline-description' } }]
102
+ }] });
103
+ const MX_TIMELINE = [
104
+ MxTimeline,
105
+ MxTimelineItem,
106
+ MxTimelineIcon,
107
+ MxTimelineTime,
108
+ MxTimelineTitle,
109
+ MxTimelineDescription,
110
+ ];
111
+
112
+ /**
113
+ * Generated bundle index. Do not edit.
114
+ */
115
+
116
+ export { MX_TIMELINE, MxTimeline, MxTimelineDescription, MxTimelineIcon, MxTimelineItem, MxTimelineTime, MxTimelineTitle };
117
+ //# sourceMappingURL=muxima-ui-core-timeline.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxima-ui-core-timeline.mjs","sources":["../../../projects/core/timeline/timeline.ts","../../../projects/core/timeline/muxima-ui-core-timeline.ts"],"sourcesContent":["import { Directive, booleanAttribute, input } from '@angular/core';\n\nexport type MxTimelineVariant = 'default' | 'accent' | 'success' | 'warning' | 'danger';\n\n/**\n * Acontecimentos por ordem, sobre uma lista ordenada nativa: o leitor de ecrã anuncia\n * \"lista, 4 itens\" e a posição de cada um.\n *\n * ```html\n * <ol mxTimeline>\n * <li mxTimelineItem variant=\"success\">\n * <time mxTimelineTime datetime=\"2026-10-27T09:40\">27 out, 09:40</time>\n * <p mxTimelineTitle>Factura paga</p>\n * <p mxTimelineDescription>Banco Mutamba pagou FT 2026/0196.</p>\n * </li>\n * </ol>\n * ```\n */\n@Directive({\n selector: 'ol[mxTimeline], ul[mxTimeline]',\n exportAs: 'mxTimeline',\n host: {\n class: 'mx-timeline',\n '[attr.data-orientation]': 'orientation() === \"vertical\" ? null : orientation()',\n '[attr.data-size]': 'size() === \"md\" ? null : size()',\n '[attr.data-align]': 'align() === \"start\" ? null : align()',\n // na horizontal pode haver scroll: o teclado tem de lá chegar\n '[attr.tabindex]': 'orientation() === \"horizontal\" ? 0 : null',\n },\n})\nexport class MxTimeline {\n readonly orientation = input<'vertical' | 'horizontal'>('vertical');\n readonly size = input<'sm' | 'md'>('md');\n /** `alternate` põe os itens alternadamente dos dois lados da linha (só vertical, ecrãs largos). */\n readonly align = input<'start' | 'alternate'>('start');\n}\n\n/**\n * Um acontecimento. O marcador fica na linha; com `pending` aparece tracejado\n * (passo ainda por acontecer). Diz isso também no texto, para o leitor de ecrã.\n */\n@Directive({\n selector: 'li[mxTimelineItem]',\n exportAs: 'mxTimelineItem',\n host: {\n class: 'mx-timeline-item',\n '[attr.data-variant]': 'variant() === \"default\" ? null : variant()',\n '[attr.data-pending]': 'pending() ? \"\" : null',\n '[attr.data-has-icon]': 'icon() ? \"\" : null',\n },\n})\nexport class MxTimelineItem {\n readonly variant = input<MxTimelineVariant>('default');\n readonly pending = input(false, { transform: booleanAttribute });\n /** Marcador maior, com espaço para um ícone (mxTimelineIcon). */\n readonly icon = input(false, { transform: booleanAttribute });\n}\n\n/** Ícone dentro do marcador (svg decorativo). Usa com `icon` no item. */\n@Directive({\n selector: '[mxTimelineIcon]',\n host: { class: 'mx-timeline-icon', 'aria-hidden': 'true' },\n})\nexport class MxTimelineIcon {}\n\n/** Data ou hora do acontecimento. Usa um `<time datetime>`. */\n@Directive({ selector: '[mxTimelineTime]', host: { class: 'mx-timeline-time' } })\nexport class MxTimelineTime {}\n\n@Directive({ selector: '[mxTimelineTitle]', host: { class: 'mx-timeline-title' } })\nexport class MxTimelineTitle {}\n\n@Directive({ selector: '[mxTimelineDescription]', host: { class: 'mx-timeline-description' } })\nexport class MxTimelineDescription {}\n\nexport const MX_TIMELINE = [\n MxTimeline,\n MxTimelineItem,\n MxTimelineIcon,\n MxTimelineTime,\n MxTimelineTitle,\n MxTimelineDescription,\n] as const;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  * Os componentes vivem em entradas secundárias, para só incluíres o que usas:
4
4
  * import { MxButton } from '@muxima-ui/core/button';
5
5
  */
6
- const MUXIMA_VERSION = '1.1.0';
6
+ const MUXIMA_VERSION = '1.2.0';
7
7
 
8
8
  /**
9
9
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"muxima-ui-core.mjs","sources":["../../../projects/core/src/public-api.ts","../../../projects/core/src/muxima-ui-core.ts"],"sourcesContent":["/*\n * Muxima UI — ponto de entrada principal.\n * Os componentes vivem em entradas secundárias, para só incluíres o que usas:\n * import { MxButton } from '@muxima-ui/core/button';\n */\nexport const MUXIMA_VERSION = '1.1.0';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;AAIG;AACI,MAAM,cAAc,GAAG;;ACL9B;;AAEG;;"}
1
+ {"version":3,"file":"muxima-ui-core.mjs","sources":["../../../projects/core/src/public-api.ts","../../../projects/core/src/muxima-ui-core.ts"],"sourcesContent":["/*\n * Muxima UI — ponto de entrada principal.\n * Os componentes vivem em entradas secundárias, para só incluíres o que usas:\n * import { MxButton } from '@muxima-ui/core/button';\n */\nexport const MUXIMA_VERSION = '1.2.0';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;AAIG;AACI,MAAM,cAAc,GAAG;;ACL9B;;AAEG;;"}