ng-comps 1.0.0 → 1.0.2
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/angular.json +9 -8
- package/documentation.json +32 -32
- package/package.json +1 -1
- package/scripts/prepare-package.mjs +38 -19
- package/src/app/components/alert/mf-alert.component.spec.ts +2 -2
- package/src/app/components/alert/mf-alert.component.ts +1 -1
- package/src/app/components/chip/mf-chip.component.ts +1 -1
- package/src/app/components/datepicker/mf-datepicker.component.spec.ts +4 -4
- package/src/app/components/datepicker/mf-datepicker.component.ts +1 -1
- package/src/app/components/dialog/mf-dialog.component.ts +1 -1
- package/src/app/components/dialog/mf-dialog.service.spec.ts +2 -2
- package/src/app/components/menu/mf-menu.component.spec.ts +1 -1
- package/src/app/components/menu/mf-menu.component.ts +1 -1
- package/src/app/components/progress-bar/mf-progress-bar.component.spec.ts +2 -2
- package/src/app/components/progress-spinner/mf-progress-spinner.component.spec.ts +3 -3
- package/src/app/components/sidenav/mf-sidenav.component.ts +2 -2
- package/src/app/components/table/mf-table.component.ts +1 -1
- package/src/stories/About.mdx +72 -72
- package/src/stories/Welcome.mdx +26 -27
- package/src/stories/mf-a11y-contracts.stories.ts +49 -49
- package/src/stories/mf-autocomplete.stories.ts +194 -188
- package/src/stories/mf-button.stories.ts +152 -156
- package/src/stories/mf-card.stories.ts +147 -148
- package/src/stories/mf-checkbox.stories.ts +88 -88
- package/src/stories/mf-datepicker.stories.ts +118 -118
- package/src/stories/mf-dialog.stories.ts +159 -167
- package/src/stories/mf-form-field.stories.ts +108 -108
- package/src/stories/mf-grid-list.stories.ts +104 -105
- package/src/stories/mf-icon.stories.ts +133 -130
- package/src/stories/mf-input.stories.ts +158 -158
- package/src/stories/mf-menu.stories.ts +10 -10
- package/src/stories/mf-progress-bar.stories.ts +119 -119
- package/src/stories/mf-progress-spinner.stories.ts +124 -124
- package/src/stories/mf-radio-button.stories.ts +111 -111
- package/src/stories/mf-select.stories.ts +184 -178
- package/src/stories/mf-sidenav.stories.ts +331 -334
- package/src/stories/mf-table.stories.ts +13 -13
- package/src/stories/mf-toolbar.stories.ts +112 -112
package/angular.json
CHANGED
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
"sourceRoot": "src",
|
|
15
15
|
"prefix": "app",
|
|
16
16
|
"architect": {
|
|
17
|
-
"build": {
|
|
18
|
-
"builder": "@angular/build:application",
|
|
19
|
-
"options": {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
"build": {
|
|
18
|
+
"builder": "@angular/build:application",
|
|
19
|
+
"options": {
|
|
20
|
+
"outputPath": "dist/ng-comps-demo",
|
|
21
|
+
"browser": "src/main.ts",
|
|
22
|
+
"tsConfig": "tsconfig.app.json",
|
|
23
|
+
"assets": [
|
|
24
|
+
{
|
|
25
|
+
"glob": "**/*",
|
|
25
26
|
"input": "public"
|
|
26
27
|
}
|
|
27
28
|
],
|
package/documentation.json
CHANGED
|
@@ -315,12 +315,12 @@
|
|
|
315
315
|
},
|
|
316
316
|
{
|
|
317
317
|
"name": "MfMenuItem",
|
|
318
|
-
"id": "interface-MfMenuItem-
|
|
318
|
+
"id": "interface-MfMenuItem-ff06e477a6f642203008fe22dad8fe3b6de09c52d8444baabaed7b35768e17479791588409c2f30a778750ee29cab09a0f67b35a7245097912fcb176a2e69b24",
|
|
319
319
|
"file": "src/app/components/menu/mf-menu.component.ts",
|
|
320
320
|
"deprecated": false,
|
|
321
321
|
"deprecationMessage": "",
|
|
322
322
|
"type": "interface",
|
|
323
|
-
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatMenuModule } from '@angular/material/menu';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport interface MfMenuItem {\r\n label: string;\r\n icon?: string;\r\n disabled?: boolean;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Menu de la librería ng-comps.\r\n * Envuelve Angular Material `mat-menu` y expone una API uniforme\r\n * con look and feel de marca.\r\n */\r\n@Component({\r\n selector: 'mf-menu',\r\n imports: [MatMenuModule, MatButtonModule, MatIconModule],\r\n template: `\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerFor]=\"menu\"\r\n [class]=\"triggerClasses()\"\r\n [attr.aria-label]=\"triggerLabel()\"\r\n >\r\n <mat-icon>{{ triggerIcon() }}</mat-icon>\r\n </button>\r\n <mat-menu #menu=\"matMenu\" [class]=\"hostClasses()\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"item.disabled ?? false\"\r\n (click)=\"mfItemClick.emit(item.value)\"\r\n >\r\n @if (item.icon) {\r\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n }\r\n <span>{{ item.label }}</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n `,\r\n styleUrl: './mf-menu.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfMenuComponent {\r\n /** Items del menú */\r\n readonly items = input.required<MfMenuItem[]>();\r\n /** Icono del trigger */\r\n readonly triggerIcon = input<string>('more_vert');\r\n /** Label accesible del trigger */\r\n readonly triggerLabel = input<string>('
|
|
323
|
+
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatMenuModule } from '@angular/material/menu';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport interface MfMenuItem {\r\n label: string;\r\n icon?: string;\r\n disabled?: boolean;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Menu de la librería ng-comps.\r\n * Envuelve Angular Material `mat-menu` y expone una API uniforme\r\n * con look and feel de marca.\r\n */\r\n@Component({\r\n selector: 'mf-menu',\r\n imports: [MatMenuModule, MatButtonModule, MatIconModule],\r\n template: `\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerFor]=\"menu\"\r\n [class]=\"triggerClasses()\"\r\n [attr.aria-label]=\"triggerLabel()\"\r\n >\r\n <mat-icon>{{ triggerIcon() }}</mat-icon>\r\n </button>\r\n <mat-menu #menu=\"matMenu\" [class]=\"hostClasses()\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"item.disabled ?? false\"\r\n (click)=\"mfItemClick.emit(item.value)\"\r\n >\r\n @if (item.icon) {\r\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n }\r\n <span>{{ item.label }}</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n `,\r\n styleUrl: './mf-menu.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfMenuComponent {\r\n /** Items del menú */\r\n readonly items = input.required<MfMenuItem[]>();\r\n /** Icono del trigger */\r\n readonly triggerIcon = input<string>('more_vert');\r\n /** Label accesible del trigger */\r\n readonly triggerLabel = input<string>('Open menu');\n\r\n readonly mfItemClick = output<string>();\r\n\r\n readonly hostClasses = computed(() => 'mf-menu');\r\n readonly triggerClasses = computed(() => 'mf-menu__trigger');\r\n}\r\n",
|
|
324
324
|
"properties": [
|
|
325
325
|
{
|
|
326
326
|
"name": "disabled",
|
|
@@ -463,12 +463,12 @@
|
|
|
463
463
|
},
|
|
464
464
|
{
|
|
465
465
|
"name": "MfSidenavNavItem",
|
|
466
|
-
"id": "interface-MfSidenavNavItem-
|
|
466
|
+
"id": "interface-MfSidenavNavItem-8f5a840ce11cea1bccb1a90dd5eda52ae12a04fd6ee1a951df332e76ea192a41aa591f8bb0f5993a6aa9a8b0107f070d9c13e9d2c638d2fde0886ba198d84c01",
|
|
467
467
|
"file": "src/app/components/sidenav/mf-sidenav.component.ts",
|
|
468
468
|
"deprecated": false,
|
|
469
469
|
"deprecationMessage": "",
|
|
470
470
|
"type": "interface",
|
|
471
|
-
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatSidenavModule } from '@angular/material/sidenav';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfSidenavMode = 'over' | 'push' | 'side';\r\nexport type MfSidenavPosition = 'start' | 'end';\r\n\r\nexport interface MfSidenavNavItem {\r\n /** Nombre del icono Material (e.g. 'home', 'dashboard') */\r\n icon: string;\r\n /** Texto de la etiqueta */\r\n label: string;\r\n /** Identificador único del ítem */\r\n id: string;\r\n /** Ítem activo/seleccionado */\r\n active?: boolean;\r\n /** Deshabilitar el ítem */\r\n disabled?: boolean;\r\n /** Número de badge (0 oculta el badge) */\r\n badge?: number;\r\n}\r\n\r\n/**\r\n * Panel lateral de la librería ng-comps.\r\n * Envuelve Angular Material `mat-sidenav-container` y expone una API uniforme\r\n * con look and feel de marca.\r\n *\r\n * Dos formas de uso:\r\n * 1. **Navitems declarativos** — Proporciona `navItems`, `headerTitle` e icono.\r\n * 2. **Content projection** — Proyecta `[mfSidenavContent]` para control total.\r\n *\r\n * El contenido principal se proyecta sin atributo.\r\n */\r\n@Component({\r\n selector: 'mf-sidenav',\r\n imports: [MatSidenavModule, MatIconModule],\r\n template: `\r\n <mat-sidenav-container [class]=\"containerClasses()\" [hasBackdrop]=\"hasBackdrop()\">\r\n <mat-sidenav\r\n [class]=\"sidenavClasses()\"\r\n [mode]=\"mode()\"\r\n [position]=\"position()\"\r\n [opened]=\"opened()\"\r\n [style.width]=\"sidenavWidth()\"\r\n (openedChange)=\"mfOpenedChange.emit($event)\"\r\n >\r\n @if (navItems().length > 0) {\r\n <div class=\"mf-sidenav__nav\">\r\n @if (headerTitle()) {\r\n <div class=\"mf-sidenav__header\">\r\n @if (headerIcon()) {\r\n <mat-icon class=\"mf-sidenav__header-icon\" aria-hidden=\"true\">{{ headerIcon() }}</mat-icon>\r\n }\r\n <span class=\"mf-sidenav__header-title\">{{ headerTitle() }}</span>\r\n </div>\r\n }\r\n <nav class=\"mf-sidenav__menu\" [attr.aria-label]=\"navAriaLabel()\">\r\n @for (item of navItems(); track item.id) {\r\n <button\r\n type=\"button\"\r\n class=\"mf-sidenav__item\"\r\n [class.mf-sidenav__item--active]=\"item.active\"\r\n [class.mf-sidenav__item--disabled]=\"item.disabled\"\r\n [disabled]=\"item.disabled ?? false\"\r\n [attr.aria-current]=\"item.active ? 'page' : null\"\r\n (click)=\"!item.disabled && mfNavItemClick.emit(item)\"\r\n >\r\n <mat-icon class=\"mf-sidenav__item-icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n <span class=\"mf-sidenav__item-label\">{{ item.label }}</span>\r\n @if (item.badge && item.badge > 0) {\r\n <span class=\"mf-sidenav__item-badge\" aria-label=\"{{ item.badge }}
|
|
471
|
+
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatSidenavModule } from '@angular/material/sidenav';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfSidenavMode = 'over' | 'push' | 'side';\r\nexport type MfSidenavPosition = 'start' | 'end';\r\n\r\nexport interface MfSidenavNavItem {\r\n /** Nombre del icono Material (e.g. 'home', 'dashboard') */\r\n icon: string;\r\n /** Texto de la etiqueta */\r\n label: string;\r\n /** Identificador único del ítem */\r\n id: string;\r\n /** Ítem activo/seleccionado */\r\n active?: boolean;\r\n /** Deshabilitar el ítem */\r\n disabled?: boolean;\r\n /** Número de badge (0 oculta el badge) */\r\n badge?: number;\r\n}\r\n\r\n/**\r\n * Panel lateral de la librería ng-comps.\r\n * Envuelve Angular Material `mat-sidenav-container` y expone una API uniforme\r\n * con look and feel de marca.\r\n *\r\n * Dos formas de uso:\r\n * 1. **Navitems declarativos** — Proporciona `navItems`, `headerTitle` e icono.\r\n * 2. **Content projection** — Proyecta `[mfSidenavContent]` para control total.\r\n *\r\n * El contenido principal se proyecta sin atributo.\r\n */\r\n@Component({\r\n selector: 'mf-sidenav',\r\n imports: [MatSidenavModule, MatIconModule],\r\n template: `\r\n <mat-sidenav-container [class]=\"containerClasses()\" [hasBackdrop]=\"hasBackdrop()\">\r\n <mat-sidenav\r\n [class]=\"sidenavClasses()\"\r\n [mode]=\"mode()\"\r\n [position]=\"position()\"\r\n [opened]=\"opened()\"\r\n [style.width]=\"sidenavWidth()\"\r\n (openedChange)=\"mfOpenedChange.emit($event)\"\r\n >\r\n @if (navItems().length > 0) {\r\n <div class=\"mf-sidenav__nav\">\r\n @if (headerTitle()) {\r\n <div class=\"mf-sidenav__header\">\r\n @if (headerIcon()) {\r\n <mat-icon class=\"mf-sidenav__header-icon\" aria-hidden=\"true\">{{ headerIcon() }}</mat-icon>\r\n }\r\n <span class=\"mf-sidenav__header-title\">{{ headerTitle() }}</span>\r\n </div>\r\n }\r\n <nav class=\"mf-sidenav__menu\" [attr.aria-label]=\"navAriaLabel()\">\r\n @for (item of navItems(); track item.id) {\r\n <button\r\n type=\"button\"\r\n class=\"mf-sidenav__item\"\r\n [class.mf-sidenav__item--active]=\"item.active\"\r\n [class.mf-sidenav__item--disabled]=\"item.disabled\"\r\n [disabled]=\"item.disabled ?? false\"\r\n [attr.aria-current]=\"item.active ? 'page' : null\"\r\n (click)=\"!item.disabled && mfNavItemClick.emit(item)\"\r\n >\r\n <mat-icon class=\"mf-sidenav__item-icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n <span class=\"mf-sidenav__item-label\">{{ item.label }}</span>\r\n @if (item.badge && item.badge > 0) {\r\n <span class=\"mf-sidenav__item-badge\" aria-label=\"{{ item.badge }} notifications\">\n {{ item.badge > 99 ? '99+' : item.badge }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </nav>\r\n </div>\r\n } @else {\r\n <ng-content select=\"[mfSidenavContent]\" />\r\n }\r\n </mat-sidenav>\r\n <mat-sidenav-content class=\"mf-sidenav__main\">\r\n <ng-content />\r\n </mat-sidenav-content>\r\n </mat-sidenav-container>\r\n `,\r\n styleUrl: './mf-sidenav.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfSidenavComponent {\r\n /** Abierto o cerrado */\r\n readonly opened = input(false);\r\n /** Modo de apertura */\r\n readonly mode = input<MfSidenavMode>('side');\r\n /** Posición del panel */\r\n readonly position = input<MfSidenavPosition>('start');\r\n /** Muestra backdrop al abrir */\r\n readonly hasBackdrop = input<boolean | null>(null);\r\n /** Ancho del panel lateral */\r\n readonly sidenavWidth = input('260px');\r\n /** Ítems de navegación declarativos */\r\n readonly navItems = input<MfSidenavNavItem[]>([]);\r\n /** Título de la cabecera del sidenav */\r\n readonly headerTitle = input<string | undefined>(undefined);\r\n /** Icono Material de la cabecera */\r\n readonly headerIcon = input<string | undefined>(undefined);\r\n /** Aria-label del elemento nav */\r\n readonly navAriaLabel = input('Primary navigation');\n\r\n readonly mfOpenedChange = output<boolean>();\r\n /** Emite el ítem de navegación pulsado */\r\n readonly mfNavItemClick = output<MfSidenavNavItem>();\r\n\r\n readonly containerClasses = computed(() => 'mf-sidenav-container');\r\n\r\n readonly sidenavClasses = computed(() => {\r\n return `mf-sidenav mf-sidenav--${this.mode()}`;\r\n });\r\n}\r\n",
|
|
472
472
|
"properties": [
|
|
473
473
|
{
|
|
474
474
|
"name": "active",
|
|
@@ -684,12 +684,12 @@
|
|
|
684
684
|
},
|
|
685
685
|
{
|
|
686
686
|
"name": "MfTableColumn",
|
|
687
|
-
"id": "interface-MfTableColumn-
|
|
687
|
+
"id": "interface-MfTableColumn-6369889e22ebd32d501cc29b2a48c86342cf5122bc6a7b5fb94a8c5cc889322854baedf9b1fbf52341440e0aad32cfe087081a9a49f2693ba78edd481bec963c",
|
|
688
688
|
"file": "src/app/components/table/mf-table.component.ts",
|
|
689
689
|
"deprecated": false,
|
|
690
690
|
"deprecationMessage": "",
|
|
691
691
|
"type": "interface",
|
|
692
|
-
"sourceCode": "import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n} from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatTableModule } from '@angular/material/table';\n\nexport interface MfTableColumn {\n key: string;\n header: string;\n sortable?: boolean;\n}\n\nexport type MfTableVariant = 'default' | 'striped' | 'bordered';\n\n/**\n * Table de la librerÃa ng-comps.\n * Envuelve Angular Material `mat-table` y expone una API uniforme\n * con look and feel de marca. Ideal para dashboards y paneles de datos.\n */\n@Component({\n selector: 'mf-table',\n imports: [MatTableModule, MatSortModule, MatButtonModule, MatIconModule],\n template: `\n <div class=\"mf-table__wrapper\" [class]=\"hostClasses()\">\n <table\n mat-table\n [dataSource]=\"data()\"\n matSort\n (matSortChange)=\"mfSortChange.emit($event)\"\n >\n @for (col of columns(); track col.key) {\n <ng-container [matColumnDef]=\"col.key\">\n @if (col.sortable) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header>{{ col.header }}</th>\n } @else {\n <th mat-header-cell *matHeaderCellDef>{{ col.header }}</th>\n }\n <td mat-cell *matCellDef=\"let row\">{{ row[col.key] }}</td>\n </ng-container>\n }\n\n @if (rowActionLabel()) {\n <ng-container [matColumnDef]=\"actionColumnKey\">\n <th mat-header-cell *matHeaderCellDef class=\"mf-table__actions-header\">\n {{ rowActionHeader() }}\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mf-table__actions-cell\">\n <button\n mat-button\n type=\"button\"\n class=\"mf-table__action\"\n [attr.aria-label]=\"getRowActionAriaLabel(row)\"\n (click)=\"emitRowAction(row)\"\n >\n {{ rowActionLabel() }}\n </button>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns()\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns()\"></tr>\n </table>\n </div>\n `,\n styleUrl: './mf-table.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfTableComponent {\n protected readonly actionColumnKey = 'mf-row-action';\n\n /** Columnas de la tabla */\n readonly columns = input.required<MfTableColumn[]>();\n /** Datos de la tabla */\n readonly data = input.required<Record<string, unknown>[]>();\n /** Variante visual */\n readonly variant = input<MfTableVariant>('default');\n /** Texto visible del botón de acción por fila */\n readonly rowActionLabel = input<string | undefined>(undefined);\n /** Cabecera visible de la columna de acción */\n readonly rowActionHeader = input('
|
|
692
|
+
"sourceCode": "import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n} from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatTableModule } from '@angular/material/table';\n\nexport interface MfTableColumn {\n key: string;\n header: string;\n sortable?: boolean;\n}\n\nexport type MfTableVariant = 'default' | 'striped' | 'bordered';\n\n/**\n * Table de la librerÃa ng-comps.\n * Envuelve Angular Material `mat-table` y expone una API uniforme\n * con look and feel de marca. Ideal para dashboards y paneles de datos.\n */\n@Component({\n selector: 'mf-table',\n imports: [MatTableModule, MatSortModule, MatButtonModule, MatIconModule],\n template: `\n <div class=\"mf-table__wrapper\" [class]=\"hostClasses()\">\n <table\n mat-table\n [dataSource]=\"data()\"\n matSort\n (matSortChange)=\"mfSortChange.emit($event)\"\n >\n @for (col of columns(); track col.key) {\n <ng-container [matColumnDef]=\"col.key\">\n @if (col.sortable) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header>{{ col.header }}</th>\n } @else {\n <th mat-header-cell *matHeaderCellDef>{{ col.header }}</th>\n }\n <td mat-cell *matCellDef=\"let row\">{{ row[col.key] }}</td>\n </ng-container>\n }\n\n @if (rowActionLabel()) {\n <ng-container [matColumnDef]=\"actionColumnKey\">\n <th mat-header-cell *matHeaderCellDef class=\"mf-table__actions-header\">\n {{ rowActionHeader() }}\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mf-table__actions-cell\">\n <button\n mat-button\n type=\"button\"\n class=\"mf-table__action\"\n [attr.aria-label]=\"getRowActionAriaLabel(row)\"\n (click)=\"emitRowAction(row)\"\n >\n {{ rowActionLabel() }}\n </button>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns()\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns()\"></tr>\n </table>\n </div>\n `,\n styleUrl: './mf-table.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfTableComponent {\n protected readonly actionColumnKey = 'mf-row-action';\n\n /** Columnas de la tabla */\n readonly columns = input.required<MfTableColumn[]>();\n /** Datos de la tabla */\n readonly data = input.required<Record<string, unknown>[]>();\n /** Variante visual */\n readonly variant = input<MfTableVariant>('default');\n /** Texto visible del botón de acción por fila */\n readonly rowActionLabel = input<string | undefined>(undefined);\n /** Cabecera visible de la columna de acción */\n readonly rowActionHeader = input('Actions');\n readonly rowActionAriaLabel = input<\n ((row: Record<string, unknown>) => string) | undefined\n >(undefined);\n\n readonly mfSortChange = output<Sort>();\n readonly mfRowAction = output<Record<string, unknown>>();\n /** @deprecated usa `mfRowAction` para interacciones explÃcitas por fila */\n readonly mfRowClick = output<Record<string, unknown>>();\n\n readonly displayedColumns = computed(() => {\n const columns = this.columns().map((column) => column.key);\n if (this.rowActionLabel()) {\n columns.push(this.actionColumnKey);\n }\n return columns;\n });\n\n readonly hostClasses = computed(() => {\n return ['mf-table', `mf-table--${this.variant()}`].join(' ');\n });\n\n emitRowAction(row: Record<string, unknown>): void {\n this.mfRowAction.emit(row);\n this.mfRowClick.emit(row);\n }\n\n getRowActionAriaLabel(row: Record<string, unknown>): string | null {\n return this.rowActionAriaLabel()?.(row) ?? this.rowActionLabel() ?? null;\n }\n}\n",
|
|
693
693
|
"properties": [
|
|
694
694
|
{
|
|
695
695
|
"name": "header",
|
|
@@ -1364,7 +1364,7 @@
|
|
|
1364
1364
|
},
|
|
1365
1365
|
{
|
|
1366
1366
|
"name": "MfAlertComponent",
|
|
1367
|
-
"id": "component-MfAlertComponent-
|
|
1367
|
+
"id": "component-MfAlertComponent-94b7ecce855041f9b5d43f8c6ea00f36a004301998d50d2720d44357feccf9475cd1f4cd0cb3c6ddc428848095ac64b6878145e6be10b3486148af7067c49eb5",
|
|
1368
1368
|
"file": "src/app/components/alert/mf-alert.component.ts",
|
|
1369
1369
|
"changeDetection": "ChangeDetectionStrategy.OnPush",
|
|
1370
1370
|
"encapsulation": [],
|
|
@@ -1375,7 +1375,7 @@
|
|
|
1375
1375
|
"selector": "mf-alert",
|
|
1376
1376
|
"styleUrls": [],
|
|
1377
1377
|
"styles": [],
|
|
1378
|
-
"template": "<div [class]=\"hostClasses()\" role=\"alert\">\n <mat-icon class=\"mf-alert__icon\" aria-hidden=\"true\">{{ iconName() }}</mat-icon>\n <div class=\"mf-alert__content\">\n @if (title()) {\n <strong class=\"mf-alert__title\">{{ title() }}</strong>\n }\n <span class=\"mf-alert__message\">{{ message() }}</span>\n </div>\n @if (dismissible()) {\n <button\n class=\"mf-alert__close\"\n (click)=\"mfDismiss.emit()\"\n [attr.aria-label]=\"'
|
|
1378
|
+
"template": "<div [class]=\"hostClasses()\" role=\"alert\">\n <mat-icon class=\"mf-alert__icon\" aria-hidden=\"true\">{{ iconName() }}</mat-icon>\n <div class=\"mf-alert__content\">\n @if (title()) {\n <strong class=\"mf-alert__title\">{{ title() }}</strong>\n }\n <span class=\"mf-alert__message\">{{ message() }}</span>\n </div>\n @if (dismissible()) {\n <button\n class=\"mf-alert__close\"\n (click)=\"mfDismiss.emit()\"\n [attr.aria-label]=\"'Close alert'\"\n >\n <mat-icon aria-hidden=\"true\">close</mat-icon>\n </button>\n }\n</div>\n",
|
|
1379
1379
|
"templateUrl": [],
|
|
1380
1380
|
"viewProviders": [],
|
|
1381
1381
|
"hostDirectives": [],
|
|
@@ -1504,7 +1504,7 @@
|
|
|
1504
1504
|
"description": "<p>Alerta de la librería ng-comps.\nComponente de banner para mensajes de sistema, alertas y notificaciones.\nIdeal para dashboards y paneles administrativos.</p>\n",
|
|
1505
1505
|
"rawdescription": "\n\nAlerta de la librería ng-comps.\nComponente de banner para mensajes de sistema, alertas y notificaciones.\nIdeal para dashboards y paneles administrativos.\n",
|
|
1506
1506
|
"type": "component",
|
|
1507
|
-
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfAlertSeverity = 'info' | 'success' | 'warning' | 'error';\r\n\r\n/**\r\n * Alerta de la librería ng-comps.\r\n * Componente de banner para mensajes de sistema, alertas y notificaciones.\r\n * Ideal para dashboards y paneles administrativos.\r\n */\r\n@Component({\r\n selector: 'mf-alert',\r\n imports: [MatIconModule],\r\n template: `\r\n <div [class]=\"hostClasses()\" role=\"alert\">\r\n <mat-icon class=\"mf-alert__icon\" aria-hidden=\"true\">{{ iconName() }}</mat-icon>\r\n <div class=\"mf-alert__content\">\r\n @if (title()) {\r\n <strong class=\"mf-alert__title\">{{ title() }}</strong>\r\n }\r\n <span class=\"mf-alert__message\">{{ message() }}</span>\r\n </div>\r\n @if (dismissible()) {\r\n <button\r\n class=\"mf-alert__close\"\r\n (click)=\"mfDismiss.emit()\"\r\n [attr.aria-label]=\"'
|
|
1507
|
+
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfAlertSeverity = 'info' | 'success' | 'warning' | 'error';\r\n\r\n/**\r\n * Alerta de la librería ng-comps.\r\n * Componente de banner para mensajes de sistema, alertas y notificaciones.\r\n * Ideal para dashboards y paneles administrativos.\r\n */\r\n@Component({\r\n selector: 'mf-alert',\r\n imports: [MatIconModule],\r\n template: `\r\n <div [class]=\"hostClasses()\" role=\"alert\">\r\n <mat-icon class=\"mf-alert__icon\" aria-hidden=\"true\">{{ iconName() }}</mat-icon>\r\n <div class=\"mf-alert__content\">\r\n @if (title()) {\r\n <strong class=\"mf-alert__title\">{{ title() }}</strong>\r\n }\r\n <span class=\"mf-alert__message\">{{ message() }}</span>\r\n </div>\r\n @if (dismissible()) {\r\n <button\r\n class=\"mf-alert__close\"\r\n (click)=\"mfDismiss.emit()\"\r\n [attr.aria-label]=\"'Close alert'\"\n >\r\n <mat-icon aria-hidden=\"true\">close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n `,\r\n styleUrl: './mf-alert.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfAlertComponent {\r\n /** Mensaje principal */\r\n readonly message = input.required<string>();\r\n /** Título opcional */\r\n readonly title = input<string | undefined>(undefined);\r\n /** Severidad de la alerta */\r\n readonly severity = input<MfAlertSeverity>('info');\r\n /** Se puede cerrar */\r\n readonly dismissible = input(false);\r\n\r\n readonly mfDismiss = output<void>();\r\n\r\n readonly iconName = computed(() => {\r\n const map: Record<MfAlertSeverity, string> = {\r\n info: 'info',\r\n success: 'check_circle',\r\n warning: 'warning',\r\n error: 'error',\r\n };\r\n return map[this.severity()];\r\n });\r\n\r\n readonly hostClasses = computed(() => {\r\n return ['mf-alert', `mf-alert--${this.severity()}`].join(' ');\r\n });\r\n}\r\n",
|
|
1508
1508
|
"styleUrl": "./mf-alert.component.css",
|
|
1509
1509
|
"assetsDirs": [],
|
|
1510
1510
|
"styleUrlsData": "",
|
|
@@ -4183,7 +4183,7 @@
|
|
|
4183
4183
|
},
|
|
4184
4184
|
{
|
|
4185
4185
|
"name": "MfChipComponent",
|
|
4186
|
-
"id": "component-MfChipComponent-
|
|
4186
|
+
"id": "component-MfChipComponent-f3d0bef0385aa0ba629ff50befd6ffc00db30834be47fb9bc795dcb3779cba58cc75b5557491232f88b2c135eeedfb93dad9e7e5c172bfbab4efc2365cd2fe23",
|
|
4187
4187
|
"file": "src/app/components/chip/mf-chip.component.ts",
|
|
4188
4188
|
"changeDetection": "ChangeDetectionStrategy.OnPush",
|
|
4189
4189
|
"encapsulation": [],
|
|
@@ -4194,7 +4194,7 @@
|
|
|
4194
4194
|
"selector": "mf-chip",
|
|
4195
4195
|
"styleUrls": [],
|
|
4196
4196
|
"styles": [],
|
|
4197
|
-
"template": "@if (removable()) {\n <mat-chip\n [highlighted]=\"selected()\"\n [disabled]=\"disabled()\"\n [class]=\"hostClasses()\"\n (removed)=\"mfRemoved.emit()\"\n >\n @if (leadingIcon()) {\n <mat-icon matChipAvatar aria-hidden=\"true\">{{ leadingIcon() }}</mat-icon>\n }\n {{ label() }}\n <button matChipRemove [attr.aria-label]=\"'
|
|
4197
|
+
"template": "@if (removable()) {\n <mat-chip\n [highlighted]=\"selected()\"\n [disabled]=\"disabled()\"\n [class]=\"hostClasses()\"\n (removed)=\"mfRemoved.emit()\"\n >\n @if (leadingIcon()) {\n <mat-icon matChipAvatar aria-hidden=\"true\">{{ leadingIcon() }}</mat-icon>\n }\n {{ label() }}\n <button matChipRemove [attr.aria-label]=\"'Remove ' + label()\">\n <mat-icon>cancel</mat-icon>\n </button>\n </mat-chip>\n} @else {\n <mat-chip\n [highlighted]=\"selected()\"\n [disabled]=\"disabled()\"\n [class]=\"hostClasses()\"\n >\n @if (leadingIcon()) {\n <mat-icon matChipAvatar aria-hidden=\"true\">{{ leadingIcon() }}</mat-icon>\n }\n {{ label() }}\n </mat-chip>\n}\n",
|
|
4198
4198
|
"templateUrl": [],
|
|
4199
4199
|
"viewProviders": [],
|
|
4200
4200
|
"hostDirectives": [],
|
|
@@ -4359,7 +4359,7 @@
|
|
|
4359
4359
|
"description": "<p>Chip de la librería ng-comps.\nEnvuelve Angular Material <code>mat-chip</code> y expone una API uniforme\ncon look and feel de marca. Ideal para tags, filtros y etiquetas.</p>\n",
|
|
4360
4360
|
"rawdescription": "\n\nChip de la librería ng-comps.\nEnvuelve Angular Material `mat-chip` y expone una API uniforme\ncon look and feel de marca. Ideal para tags, filtros y etiquetas.\n",
|
|
4361
4361
|
"type": "component",
|
|
4362
|
-
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatChipsModule } from '@angular/material/chips';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfChipVariant = 'filled' | 'outlined';\r\nexport type MfChipColor = 'brand' | 'accent' | 'error' | 'neutral';\r\n\r\n/**\r\n * Chip de la librería ng-comps.\r\n * Envuelve Angular Material `mat-chip` y expone una API uniforme\r\n * con look and feel de marca. Ideal para tags, filtros y etiquetas.\r\n */\r\n@Component({\r\n selector: 'mf-chip',\r\n imports: [MatChipsModule, MatIconModule],\r\n template: `\r\n @if (removable()) {\r\n <mat-chip\r\n [highlighted]=\"selected()\"\r\n [disabled]=\"disabled()\"\r\n [class]=\"hostClasses()\"\r\n (removed)=\"mfRemoved.emit()\"\r\n >\r\n @if (leadingIcon()) {\r\n <mat-icon matChipAvatar aria-hidden=\"true\">{{ leadingIcon() }}</mat-icon>\r\n }\r\n {{ label() }}\r\n <button matChipRemove [attr.aria-label]=\"'
|
|
4362
|
+
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatChipsModule } from '@angular/material/chips';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfChipVariant = 'filled' | 'outlined';\r\nexport type MfChipColor = 'brand' | 'accent' | 'error' | 'neutral';\r\n\r\n/**\r\n * Chip de la librería ng-comps.\r\n * Envuelve Angular Material `mat-chip` y expone una API uniforme\r\n * con look and feel de marca. Ideal para tags, filtros y etiquetas.\r\n */\r\n@Component({\r\n selector: 'mf-chip',\r\n imports: [MatChipsModule, MatIconModule],\r\n template: `\r\n @if (removable()) {\r\n <mat-chip\r\n [highlighted]=\"selected()\"\r\n [disabled]=\"disabled()\"\r\n [class]=\"hostClasses()\"\r\n (removed)=\"mfRemoved.emit()\"\r\n >\r\n @if (leadingIcon()) {\r\n <mat-icon matChipAvatar aria-hidden=\"true\">{{ leadingIcon() }}</mat-icon>\r\n }\r\n {{ label() }}\r\n <button matChipRemove [attr.aria-label]=\"'Remove ' + label()\">\n <mat-icon>cancel</mat-icon>\r\n </button>\r\n </mat-chip>\r\n } @else {\r\n <mat-chip\r\n [highlighted]=\"selected()\"\r\n [disabled]=\"disabled()\"\r\n [class]=\"hostClasses()\"\r\n >\r\n @if (leadingIcon()) {\r\n <mat-icon matChipAvatar aria-hidden=\"true\">{{ leadingIcon() }}</mat-icon>\r\n }\r\n {{ label() }}\r\n </mat-chip>\r\n }\r\n `,\r\n styleUrl: './mf-chip.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfChipComponent {\r\n /** Texto del chip */\r\n readonly label = input.required<string>();\r\n /** Variante visual */\r\n readonly variant = input<MfChipVariant>('filled');\r\n /** Color semántico */\r\n readonly color = input<MfChipColor>('brand');\r\n /** Seleccionado */\r\n readonly selected = input(false);\r\n /** Puede ser removido */\r\n readonly removable = input(false);\r\n /** Deshabilitado */\r\n readonly disabled = input(false);\r\n /** Icono inicial */\r\n readonly leadingIcon = input<string | undefined>(undefined);\r\n\r\n readonly mfRemoved = output<void>();\r\n\r\n readonly hostClasses = computed(() => {\r\n const classes = ['mf-chip', `mf-chip--${this.variant()}`, `mf-chip--${this.color()}`];\r\n if (this.selected()) classes.push('mf-chip--selected');\r\n return classes.join(' ');\r\n });\r\n}\r\n",
|
|
4363
4363
|
"styleUrl": "./mf-chip.component.css",
|
|
4364
4364
|
"assetsDirs": [],
|
|
4365
4365
|
"styleUrlsData": "",
|
|
@@ -4368,7 +4368,7 @@
|
|
|
4368
4368
|
},
|
|
4369
4369
|
{
|
|
4370
4370
|
"name": "MfDatepickerComponent",
|
|
4371
|
-
"id": "component-MfDatepickerComponent-
|
|
4371
|
+
"id": "component-MfDatepickerComponent-ff055d3db19e537197b0ddea7a0271c59683cc9c01652ffa33eabeb6cd2390d55d168b03069cc2c8b57d6f6ae63973f6826d74c09de637dbf6fabbdc256d2e0e",
|
|
4372
4372
|
"file": "src/app/components/datepicker/mf-datepicker.component.ts",
|
|
4373
4373
|
"changeDetection": "ChangeDetectionStrategy.OnPush",
|
|
4374
4374
|
"encapsulation": [],
|
|
@@ -4610,7 +4610,7 @@
|
|
|
4610
4610
|
},
|
|
4611
4611
|
{
|
|
4612
4612
|
"name": "toggleAriaLabel",
|
|
4613
|
-
"defaultValue": "'
|
|
4613
|
+
"defaultValue": "'Open calendar'",
|
|
4614
4614
|
"deprecated": false,
|
|
4615
4615
|
"deprecationMessage": "",
|
|
4616
4616
|
"indexKey": "",
|
|
@@ -5121,7 +5121,7 @@
|
|
|
5121
5121
|
"description": "<p>Selector de fecha de la librerÃa ng-comps.\nEnvuelve Angular Material <code>mat-datepicker</code> y expone una API uniforme\ncon look and feel de marca.</p>\n",
|
|
5122
5122
|
"rawdescription": "\n\nSelector de fecha de la librerÃa ng-comps.\nEnvuelve Angular Material `mat-datepicker` y expone una API uniforme\ncon look and feel de marca.\n",
|
|
5123
5123
|
"type": "component",
|
|
5124
|
-
"sourceCode": "import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n computed,\n effect,\n forwardRef,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\nimport {\n ControlValueAccessor,\n NG_VALUE_ACCESSOR,\n NgControl,\n} from '@angular/forms';\nimport { ErrorStateMatcher } from '@angular/material/core';\nimport { MatNativeDateModule } from '@angular/material/core';\nimport { MatDatepickerModule } from '@angular/material/datepicker';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatInputModule } from '@angular/material/input';\nimport {\n createUniqueId,\n hasAccessibleName,\n mergeAriaIds,\n warnInDev,\n} from '../../a11y';\n\nexport type MfDatepickerSize = 'sm' | 'md' | 'lg';\n\n/**\n * Selector de fecha de la librerÃa ng-comps.\n * Envuelve Angular Material `mat-datepicker` y expone una API uniforme\n * con look and feel de marca.\n */\n@Component({\n selector: 'mf-datepicker',\n imports: [\n MatDatepickerModule,\n MatFormFieldModule,\n MatInputModule,\n MatNativeDateModule,\n MatIconModule,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => MfDatepickerComponent),\n multi: true,\n },\n ],\n template: `\n <mat-form-field [appearance]=\"'outline'\" [class]=\"hostClasses()\">\n @if (label()) {\n <mat-label>{{ label() }}</mat-label>\n }\n <input\n matInput\n [id]=\"controlId()\"\n [matDatepicker]=\"picker\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [value]=\"internalValue()\"\n [errorStateMatcher]=\"errorStateMatcher\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-invalid]=\"isInvalid() ? 'true' : null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n (dateChange)=\"onDateChange($event)\"\n (blur)=\"onBlur()\"\n />\n <mat-datepicker-toggle\n matIconSuffix\n [for]=\"picker\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n >\n <mat-icon matDatepickerToggleIcon aria-hidden=\"true\">\n calendar_month\n </mat-icon>\n </mat-datepicker-toggle>\n <mat-datepicker #picker />\n @if (hint()) {\n <mat-hint [attr.id]=\"hintId()\">{{ hint() }}</mat-hint>\n }\n </mat-form-field>\n @if (error()) {\n <p class=\"mf-datepicker__error\" [attr.id]=\"errorId()\" role=\"alert\">\n {{ error() }}\n </p>\n }\n `,\n styleUrl: './mf-datepicker.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfDatepickerComponent implements ControlValueAccessor {\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly ngControl = inject(NgControl, { self: true, optional: true });\n private readonly generatedId = createUniqueId('mf-datepicker');\n private readonly disabledFromForm = signal(false);\n protected readonly internalValue = signal<Date | null>(null);\n private onControlChange: (value: Date | null) => void = () => undefined;\n private onControlTouched: () => void = () => undefined;\n readonly errorStateMatcher: ErrorStateMatcher = {\n isErrorState: (control) =>\n Boolean(\n this.error() || (control?.invalid && (control.touched || control.dirty)),\n ),\n };\n\n /** ID del control */\n readonly id = input<string | undefined>(undefined);\n /** Etiqueta flotante del campo */\n readonly label = input<string | undefined>(undefined);\n /** Etiqueta accesible alternativa cuando no existe label visible */\n readonly ariaLabel = input<string | undefined>(undefined);\n /** Referencia externa a elementos que etiquetan el control */\n readonly ariaLabelledby = input<string | undefined>(undefined);\n /** Referencia externa a elementos descriptivos adicionales */\n readonly ariaDescribedby = input<string | undefined>(undefined);\n /** Placeholder del input */\n readonly placeholder = input('DD/MM/YYYY');\n /** Tamaño del campo */\n readonly size = input<MfDatepickerSize>('md');\n /** Deshabilitado */\n readonly disabled = input(false);\n /** Requerido */\n readonly required = input(false);\n /** Valor inicial del datepicker */\n readonly value = input<Date | null>(null);\n /** Texto de ayuda debajo del campo */\n readonly hint = input<string | undefined>(undefined);\n /** Mensaje de error */\n readonly error = input<string | undefined>(undefined);\n /** Fecha mÃnima seleccionable */\n readonly min = input<Date | null>(null);\n /** Fecha máxima seleccionable */\n readonly max = input<Date | null>(null);\n /** Ancho completo */\n readonly fullWidth = input(false);\n /** Etiqueta accesible del botón para abrir el calendario */\n readonly toggleAriaLabel = input('
|
|
5124
|
+
"sourceCode": "import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n computed,\n effect,\n forwardRef,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\nimport {\n ControlValueAccessor,\n NG_VALUE_ACCESSOR,\n NgControl,\n} from '@angular/forms';\nimport { ErrorStateMatcher } from '@angular/material/core';\nimport { MatNativeDateModule } from '@angular/material/core';\nimport { MatDatepickerModule } from '@angular/material/datepicker';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatInputModule } from '@angular/material/input';\nimport {\n createUniqueId,\n hasAccessibleName,\n mergeAriaIds,\n warnInDev,\n} from '../../a11y';\n\nexport type MfDatepickerSize = 'sm' | 'md' | 'lg';\n\n/**\n * Selector de fecha de la librerÃa ng-comps.\n * Envuelve Angular Material `mat-datepicker` y expone una API uniforme\n * con look and feel de marca.\n */\n@Component({\n selector: 'mf-datepicker',\n imports: [\n MatDatepickerModule,\n MatFormFieldModule,\n MatInputModule,\n MatNativeDateModule,\n MatIconModule,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => MfDatepickerComponent),\n multi: true,\n },\n ],\n template: `\n <mat-form-field [appearance]=\"'outline'\" [class]=\"hostClasses()\">\n @if (label()) {\n <mat-label>{{ label() }}</mat-label>\n }\n <input\n matInput\n [id]=\"controlId()\"\n [matDatepicker]=\"picker\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [value]=\"internalValue()\"\n [errorStateMatcher]=\"errorStateMatcher\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-invalid]=\"isInvalid() ? 'true' : null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n (dateChange)=\"onDateChange($event)\"\n (blur)=\"onBlur()\"\n />\n <mat-datepicker-toggle\n matIconSuffix\n [for]=\"picker\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n >\n <mat-icon matDatepickerToggleIcon aria-hidden=\"true\">\n calendar_month\n </mat-icon>\n </mat-datepicker-toggle>\n <mat-datepicker #picker />\n @if (hint()) {\n <mat-hint [attr.id]=\"hintId()\">{{ hint() }}</mat-hint>\n }\n </mat-form-field>\n @if (error()) {\n <p class=\"mf-datepicker__error\" [attr.id]=\"errorId()\" role=\"alert\">\n {{ error() }}\n </p>\n }\n `,\n styleUrl: './mf-datepicker.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfDatepickerComponent implements ControlValueAccessor {\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly ngControl = inject(NgControl, { self: true, optional: true });\n private readonly generatedId = createUniqueId('mf-datepicker');\n private readonly disabledFromForm = signal(false);\n protected readonly internalValue = signal<Date | null>(null);\n private onControlChange: (value: Date | null) => void = () => undefined;\n private onControlTouched: () => void = () => undefined;\n readonly errorStateMatcher: ErrorStateMatcher = {\n isErrorState: (control) =>\n Boolean(\n this.error() || (control?.invalid && (control.touched || control.dirty)),\n ),\n };\n\n /** ID del control */\n readonly id = input<string | undefined>(undefined);\n /** Etiqueta flotante del campo */\n readonly label = input<string | undefined>(undefined);\n /** Etiqueta accesible alternativa cuando no existe label visible */\n readonly ariaLabel = input<string | undefined>(undefined);\n /** Referencia externa a elementos que etiquetan el control */\n readonly ariaLabelledby = input<string | undefined>(undefined);\n /** Referencia externa a elementos descriptivos adicionales */\n readonly ariaDescribedby = input<string | undefined>(undefined);\n /** Placeholder del input */\n readonly placeholder = input('DD/MM/YYYY');\n /** Tamaño del campo */\n readonly size = input<MfDatepickerSize>('md');\n /** Deshabilitado */\n readonly disabled = input(false);\n /** Requerido */\n readonly required = input(false);\n /** Valor inicial del datepicker */\n readonly value = input<Date | null>(null);\n /** Texto de ayuda debajo del campo */\n readonly hint = input<string | undefined>(undefined);\n /** Mensaje de error */\n readonly error = input<string | undefined>(undefined);\n /** Fecha mÃnima seleccionable */\n readonly min = input<Date | null>(null);\n /** Fecha máxima seleccionable */\n readonly max = input<Date | null>(null);\n /** Ancho completo */\n readonly fullWidth = input(false);\n /** Etiqueta accesible del botón para abrir el calendario */\n readonly toggleAriaLabel = input('Open calendar');\n\n readonly mfChange = output<Date | null>();\n readonly mfBlur = output<void>();\n\n constructor() {\n effect(() => {\n this.internalValue.set(this.value());\n });\n\n effect(() => {\n if (\n !hasAccessibleName(\n this.label(),\n this.ariaLabel(),\n this.ariaLabelledby(),\n )\n ) {\n warnInDev(\n 'mf-datepicker requiere `label`, `ariaLabel` o `ariaLabelledby` para exponer un nombre accesible.',\n );\n }\n });\n }\n\n readonly controlId = computed(() => this.id() ?? this.generatedId);\n readonly hintId = computed(() =>\n this.hint() ? `${this.controlId()}-hint` : null,\n );\n readonly errorId = computed(() =>\n this.error() ? `${this.controlId()}-error` : null,\n );\n readonly describedBy = computed(() =>\n mergeAriaIds(this.ariaDescribedby(), this.hintId(), this.errorId()),\n );\n readonly resolvedAriaLabel = computed(() =>\n this.label() ? null : this.ariaLabel() ?? null,\n );\n readonly isDisabled = computed(\n () => this.disabled() || this.disabledFromForm(),\n );\n\n readonly hostClasses = computed(() => {\n const classes = ['mf-datepicker', `mf-datepicker--${this.size()}`];\n if (this.fullWidth()) classes.push('mf-datepicker--full');\n if (this.error()) classes.push('mf-datepicker--error');\n return classes.join(' ');\n });\n\n writeValue(value: Date | null): void {\n this.internalValue.set(value);\n this.cdr.markForCheck();\n }\n\n registerOnChange(fn: (value: Date | null) => void): void {\n this.onControlChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onControlTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.disabledFromForm.set(isDisabled);\n this.cdr.markForCheck();\n }\n\n isInvalid(): boolean {\n const control = this.ngControl?.control;\n return Boolean(\n this.error() || (control?.invalid && (control.touched || control.dirty)),\n );\n }\n\n onDateChange(event: { value: Date | null }): void {\n this.internalValue.set(event.value);\n this.onControlChange(event.value);\n this.onControlTouched();\n this.mfChange.emit(event.value);\n }\n\n onBlur(): void {\n this.onControlTouched();\n this.mfBlur.emit();\n }\n}\n",
|
|
5125
5125
|
"styleUrl": "./mf-datepicker.component.css",
|
|
5126
5126
|
"assetsDirs": [],
|
|
5127
5127
|
"styleUrlsData": "",
|
|
@@ -5141,7 +5141,7 @@
|
|
|
5141
5141
|
},
|
|
5142
5142
|
{
|
|
5143
5143
|
"name": "MfDialogComponent",
|
|
5144
|
-
"id": "component-MfDialogComponent-
|
|
5144
|
+
"id": "component-MfDialogComponent-9d0512c48eb31e1458ff65f3bd712786a094920d7a057af6ad1d0f23ba243516bb0290ad1e903db4a952cef9f182b6e2cb37646a00d69d46bb0e4f437d44d59b",
|
|
5145
5145
|
"file": "src/app/components/dialog/mf-dialog.component.ts",
|
|
5146
5146
|
"changeDetection": "ChangeDetectionStrategy.OnPush",
|
|
5147
5147
|
"encapsulation": [],
|
|
@@ -5207,7 +5207,7 @@
|
|
|
5207
5207
|
},
|
|
5208
5208
|
{
|
|
5209
5209
|
"name": "closeButtonLabel",
|
|
5210
|
-
"defaultValue": "'
|
|
5210
|
+
"defaultValue": "'Close dialog'",
|
|
5211
5211
|
"deprecated": false,
|
|
5212
5212
|
"deprecationMessage": "",
|
|
5213
5213
|
"indexKey": "",
|
|
@@ -5491,7 +5491,7 @@
|
|
|
5491
5491
|
"description": "<p>Contenido de diálogo de la librerÃa ng-comps.\nEnvuelve las directivas de Angular Material <code>mat-dialog-*</code> y expone\nuna API uniforme con look and feel de marca.</p>\n<p>Uso:</p>\n<b>Example :</b><div><pre class=\"line-numbers\"><code class=\"language-none\">dialog.open(MfDialogComponent, {\n data: { title: 'Confirmar', message: '¿Deseas continuar?' }\n});</code></pre></div>",
|
|
5492
5492
|
"rawdescription": "\n\nContenido de diálogo de la librerÃa ng-comps.\nEnvuelve las directivas de Angular Material `mat-dialog-*` y expone\nuna API uniforme con look and feel de marca.\n\nUso:\n```\ndialog.open(MfDialogComponent, {\n data: { title: 'Confirmar', message: '¿Deseas continuar?' }\n});\n```\n",
|
|
5493
5493
|
"type": "component",
|
|
5494
|
-
"sourceCode": "import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { MatDialogModule, MatDialogRef } from '@angular/material/dialog';\nimport { MatIconModule } from '@angular/material/icon';\nimport {\n createUniqueId,\n hasAccessibleName,\n mergeAriaIds,\n warnInDev,\n} from '../../a11y';\n\n/**\n * Contenido de diálogo de la librerÃa ng-comps.\n * Envuelve las directivas de Angular Material `mat-dialog-*` y expone\n * una API uniforme con look and feel de marca.\n *\n * Uso:\n * ```\n * dialog.open(MfDialogComponent, {\n * data: { title: 'Confirmar', message: '¿Deseas continuar?' }\n * });\n * ```\n */\n@Component({\n selector: 'mf-dialog',\n imports: [MatDialogModule, MatIconModule],\n template: `\n <div\n [class]=\"hostClasses()\"\n [attr.role]=\"role()\"\n aria-modal=\"true\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-labelledby]=\"computedLabelledby()\"\n [attr.aria-describedby]=\"computedDescribedby()\"\n >\n @if (title()) {\n <h2 mat-dialog-title class=\"mf-dialog__header\" [id]=\"titleId()\">\n <span class=\"mf-dialog__title\">{{ title() }}</span>\n @if (showClose()) {\n <button\n mat-icon-button\n class=\"mf-dialog__close\"\n (click)=\"onClose()\"\n [attr.aria-label]=\"closeButtonLabel()\"\n type=\"button\"\n >\n <mat-icon aria-hidden=\"true\">close</mat-icon>\n </button>\n }\n </h2>\n } @else if (showClose()) {\n <div class=\"mf-dialog__header mf-dialog__header--compact\">\n <span></span>\n <button\n mat-icon-button\n class=\"mf-dialog__close\"\n (click)=\"onClose()\"\n [attr.aria-label]=\"closeButtonLabel()\"\n type=\"button\"\n >\n <mat-icon aria-hidden=\"true\">close</mat-icon>\n </button>\n </div>\n }\n\n <div mat-dialog-content class=\"mf-dialog__content\">\n @if (message()) {\n <p class=\"mf-dialog__message\" [id]=\"descriptionId()\">{{ message() }}</p>\n }\n\n <ng-content />\n </div>\n\n @if (showActions()) {\n <div mat-dialog-actions class=\"mf-dialog__actions\">\n <ng-content select=\"[mfDialogActions]\" />\n </div>\n }\n </div>\n `,\n styleUrl: './mf-dialog.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfDialogComponent {\n private readonly dialogRef = inject(MatDialogRef<MfDialogComponent>, {\n optional: true,\n });\n private readonly generatedId = createUniqueId('mf-dialog');\n\n /** ID base del diálogo */\n readonly id = input<string | undefined>(undefined);\n /** TÃtulo del diálogo */\n readonly title = input<string | undefined>(undefined);\n /** Etiqueta accesible alternativa cuando no existe tÃtulo visible */\n readonly ariaLabel = input<string | undefined>(undefined);\n /** Referencia externa a elementos que etiquetan el diálogo */\n readonly ariaLabelledby = input<string | undefined>(undefined);\n /** Referencia externa a elementos descriptivos adicionales */\n readonly ariaDescribedby = input<string | undefined>(undefined);\n /** Mensaje descriptivo */\n readonly message = input<string | undefined>(undefined);\n /** Mostrar botón de cerrar */\n readonly showClose = input(true);\n /** Mostrar área de acciones (footer) */\n readonly showActions = input(true);\n /** Rol del diálogo */\n readonly role = input<'dialog' | 'alertdialog'>('dialog');\n /** Etiqueta accesible del botón de cierre */\n readonly closeButtonLabel = input('
|
|
5494
|
+
"sourceCode": "import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { MatDialogModule, MatDialogRef } from '@angular/material/dialog';\nimport { MatIconModule } from '@angular/material/icon';\nimport {\n createUniqueId,\n hasAccessibleName,\n mergeAriaIds,\n warnInDev,\n} from '../../a11y';\n\n/**\n * Contenido de diálogo de la librerÃa ng-comps.\n * Envuelve las directivas de Angular Material `mat-dialog-*` y expone\n * una API uniforme con look and feel de marca.\n *\n * Uso:\n * ```\n * dialog.open(MfDialogComponent, {\n * data: { title: 'Confirmar', message: '¿Deseas continuar?' }\n * });\n * ```\n */\n@Component({\n selector: 'mf-dialog',\n imports: [MatDialogModule, MatIconModule],\n template: `\n <div\n [class]=\"hostClasses()\"\n [attr.role]=\"role()\"\n aria-modal=\"true\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-labelledby]=\"computedLabelledby()\"\n [attr.aria-describedby]=\"computedDescribedby()\"\n >\n @if (title()) {\n <h2 mat-dialog-title class=\"mf-dialog__header\" [id]=\"titleId()\">\n <span class=\"mf-dialog__title\">{{ title() }}</span>\n @if (showClose()) {\n <button\n mat-icon-button\n class=\"mf-dialog__close\"\n (click)=\"onClose()\"\n [attr.aria-label]=\"closeButtonLabel()\"\n type=\"button\"\n >\n <mat-icon aria-hidden=\"true\">close</mat-icon>\n </button>\n }\n </h2>\n } @else if (showClose()) {\n <div class=\"mf-dialog__header mf-dialog__header--compact\">\n <span></span>\n <button\n mat-icon-button\n class=\"mf-dialog__close\"\n (click)=\"onClose()\"\n [attr.aria-label]=\"closeButtonLabel()\"\n type=\"button\"\n >\n <mat-icon aria-hidden=\"true\">close</mat-icon>\n </button>\n </div>\n }\n\n <div mat-dialog-content class=\"mf-dialog__content\">\n @if (message()) {\n <p class=\"mf-dialog__message\" [id]=\"descriptionId()\">{{ message() }}</p>\n }\n\n <ng-content />\n </div>\n\n @if (showActions()) {\n <div mat-dialog-actions class=\"mf-dialog__actions\">\n <ng-content select=\"[mfDialogActions]\" />\n </div>\n }\n </div>\n `,\n styleUrl: './mf-dialog.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfDialogComponent {\n private readonly dialogRef = inject(MatDialogRef<MfDialogComponent>, {\n optional: true,\n });\n private readonly generatedId = createUniqueId('mf-dialog');\n\n /** ID base del diálogo */\n readonly id = input<string | undefined>(undefined);\n /** TÃtulo del diálogo */\n readonly title = input<string | undefined>(undefined);\n /** Etiqueta accesible alternativa cuando no existe tÃtulo visible */\n readonly ariaLabel = input<string | undefined>(undefined);\n /** Referencia externa a elementos que etiquetan el diálogo */\n readonly ariaLabelledby = input<string | undefined>(undefined);\n /** Referencia externa a elementos descriptivos adicionales */\n readonly ariaDescribedby = input<string | undefined>(undefined);\n /** Mensaje descriptivo */\n readonly message = input<string | undefined>(undefined);\n /** Mostrar botón de cerrar */\n readonly showClose = input(true);\n /** Mostrar área de acciones (footer) */\n readonly showActions = input(true);\n /** Rol del diálogo */\n readonly role = input<'dialog' | 'alertdialog'>('dialog');\n /** Etiqueta accesible del botón de cierre */\n readonly closeButtonLabel = input('Close dialog');\n\n readonly mfClose = output<void>();\n\n constructor() {\n effect(() => {\n if (\n !hasAccessibleName(\n this.title(),\n this.ariaLabel(),\n this.ariaLabelledby(),\n )\n ) {\n warnInDev(\n 'mf-dialog requiere `title`, `ariaLabel` o `ariaLabelledby` para exponer un nombre accesible.',\n );\n }\n });\n }\n\n readonly dialogId = computed(() => this.id() ?? this.generatedId);\n readonly titleId = computed(() => `${this.dialogId()}-title`);\n readonly descriptionId = computed(() => `${this.dialogId()}-description`);\n readonly computedLabelledby = computed(() =>\n mergeAriaIds(\n this.ariaLabelledby(),\n this.title() ? this.titleId() : null,\n ),\n );\n readonly computedDescribedby = computed(() =>\n mergeAriaIds(\n this.ariaDescribedby(),\n this.message() ? this.descriptionId() : null,\n ),\n );\n readonly resolvedAriaLabel = computed(() =>\n this.title() ? null : this.ariaLabel() ?? null,\n );\n readonly hostClasses = computed(() => 'mf-dialog');\n\n onClose(): void {\n this.mfClose.emit();\n this.dialogRef?.close();\n }\n}\n",
|
|
5495
5495
|
"styleUrl": "./mf-dialog.component.css",
|
|
5496
5496
|
"assetsDirs": [],
|
|
5497
5497
|
"styleUrlsData": "",
|
|
@@ -6802,7 +6802,7 @@
|
|
|
6802
6802
|
},
|
|
6803
6803
|
{
|
|
6804
6804
|
"name": "MfMenuComponent",
|
|
6805
|
-
"id": "component-MfMenuComponent-
|
|
6805
|
+
"id": "component-MfMenuComponent-ff06e477a6f642203008fe22dad8fe3b6de09c52d8444baabaed7b35768e17479791588409c2f30a778750ee29cab09a0f67b35a7245097912fcb176a2e69b24",
|
|
6806
6806
|
"file": "src/app/components/menu/mf-menu.component.ts",
|
|
6807
6807
|
"changeDetection": "ChangeDetectionStrategy.OnPush",
|
|
6808
6808
|
"encapsulation": [],
|
|
@@ -6851,7 +6851,7 @@
|
|
|
6851
6851
|
},
|
|
6852
6852
|
{
|
|
6853
6853
|
"name": "triggerLabel",
|
|
6854
|
-
"defaultValue": "'
|
|
6854
|
+
"defaultValue": "'Open menu'",
|
|
6855
6855
|
"deprecated": false,
|
|
6856
6856
|
"deprecationMessage": "",
|
|
6857
6857
|
"type": "string",
|
|
@@ -6935,7 +6935,7 @@
|
|
|
6935
6935
|
"description": "<p>Menu de la librería ng-comps.\nEnvuelve Angular Material <code>mat-menu</code> y expone una API uniforme\ncon look and feel de marca.</p>\n",
|
|
6936
6936
|
"rawdescription": "\n\nMenu de la librería ng-comps.\nEnvuelve Angular Material `mat-menu` y expone una API uniforme\ncon look and feel de marca.\n",
|
|
6937
6937
|
"type": "component",
|
|
6938
|
-
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatMenuModule } from '@angular/material/menu';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport interface MfMenuItem {\r\n label: string;\r\n icon?: string;\r\n disabled?: boolean;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Menu de la librería ng-comps.\r\n * Envuelve Angular Material `mat-menu` y expone una API uniforme\r\n * con look and feel de marca.\r\n */\r\n@Component({\r\n selector: 'mf-menu',\r\n imports: [MatMenuModule, MatButtonModule, MatIconModule],\r\n template: `\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerFor]=\"menu\"\r\n [class]=\"triggerClasses()\"\r\n [attr.aria-label]=\"triggerLabel()\"\r\n >\r\n <mat-icon>{{ triggerIcon() }}</mat-icon>\r\n </button>\r\n <mat-menu #menu=\"matMenu\" [class]=\"hostClasses()\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"item.disabled ?? false\"\r\n (click)=\"mfItemClick.emit(item.value)\"\r\n >\r\n @if (item.icon) {\r\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n }\r\n <span>{{ item.label }}</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n `,\r\n styleUrl: './mf-menu.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfMenuComponent {\r\n /** Items del menú */\r\n readonly items = input.required<MfMenuItem[]>();\r\n /** Icono del trigger */\r\n readonly triggerIcon = input<string>('more_vert');\r\n /** Label accesible del trigger */\r\n readonly triggerLabel = input<string>('
|
|
6938
|
+
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatMenuModule } from '@angular/material/menu';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport interface MfMenuItem {\r\n label: string;\r\n icon?: string;\r\n disabled?: boolean;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Menu de la librería ng-comps.\r\n * Envuelve Angular Material `mat-menu` y expone una API uniforme\r\n * con look and feel de marca.\r\n */\r\n@Component({\r\n selector: 'mf-menu',\r\n imports: [MatMenuModule, MatButtonModule, MatIconModule],\r\n template: `\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerFor]=\"menu\"\r\n [class]=\"triggerClasses()\"\r\n [attr.aria-label]=\"triggerLabel()\"\r\n >\r\n <mat-icon>{{ triggerIcon() }}</mat-icon>\r\n </button>\r\n <mat-menu #menu=\"matMenu\" [class]=\"hostClasses()\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"item.disabled ?? false\"\r\n (click)=\"mfItemClick.emit(item.value)\"\r\n >\r\n @if (item.icon) {\r\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n }\r\n <span>{{ item.label }}</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n `,\r\n styleUrl: './mf-menu.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfMenuComponent {\r\n /** Items del menú */\r\n readonly items = input.required<MfMenuItem[]>();\r\n /** Icono del trigger */\r\n readonly triggerIcon = input<string>('more_vert');\r\n /** Label accesible del trigger */\r\n readonly triggerLabel = input<string>('Open menu');\n\r\n readonly mfItemClick = output<string>();\r\n\r\n readonly hostClasses = computed(() => 'mf-menu');\r\n readonly triggerClasses = computed(() => 'mf-menu__trigger');\r\n}\r\n",
|
|
6939
6939
|
"styleUrl": "./mf-menu.component.css",
|
|
6940
6940
|
"assetsDirs": [],
|
|
6941
6941
|
"styleUrlsData": "",
|
|
@@ -9017,7 +9017,7 @@
|
|
|
9017
9017
|
},
|
|
9018
9018
|
{
|
|
9019
9019
|
"name": "MfSidenavComponent",
|
|
9020
|
-
"id": "component-MfSidenavComponent-
|
|
9020
|
+
"id": "component-MfSidenavComponent-8f5a840ce11cea1bccb1a90dd5eda52ae12a04fd6ee1a951df332e76ea192a41aa591f8bb0f5993a6aa9a8b0107f070d9c13e9d2c638d2fde0886ba198d84c01",
|
|
9021
9021
|
"file": "src/app/components/sidenav/mf-sidenav.component.ts",
|
|
9022
9022
|
"changeDetection": "ChangeDetectionStrategy.OnPush",
|
|
9023
9023
|
"encapsulation": [],
|
|
@@ -9028,7 +9028,7 @@
|
|
|
9028
9028
|
"selector": "mf-sidenav",
|
|
9029
9029
|
"styleUrls": [],
|
|
9030
9030
|
"styles": [],
|
|
9031
|
-
"template": "<mat-sidenav-container [class]=\"containerClasses()\" [hasBackdrop]=\"hasBackdrop()\">\n <mat-sidenav\n [class]=\"sidenavClasses()\"\n [mode]=\"mode()\"\n [position]=\"position()\"\n [opened]=\"opened()\"\n [style.width]=\"sidenavWidth()\"\n (openedChange)=\"mfOpenedChange.emit($event)\"\n >\n @if (navItems().length > 0) {\n <div class=\"mf-sidenav__nav\">\n @if (headerTitle()) {\n <div class=\"mf-sidenav__header\">\n @if (headerIcon()) {\n <mat-icon class=\"mf-sidenav__header-icon\" aria-hidden=\"true\">{{ headerIcon() }}</mat-icon>\n }\n <span class=\"mf-sidenav__header-title\">{{ headerTitle() }}</span>\n </div>\n }\n <nav class=\"mf-sidenav__menu\" [attr.aria-label]=\"navAriaLabel()\">\n @for (item of navItems(); track item.id) {\n <button\n type=\"button\"\n class=\"mf-sidenav__item\"\n [class.mf-sidenav__item--active]=\"item.active\"\n [class.mf-sidenav__item--disabled]=\"item.disabled\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-current]=\"item.active ? 'page' : null\"\n (click)=\"!item.disabled && mfNavItemClick.emit(item)\"\n >\n <mat-icon class=\"mf-sidenav__item-icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"mf-sidenav__item-label\">{{ item.label }}</span>\n @if (item.badge && item.badge > 0) {\n <span class=\"mf-sidenav__item-badge\" aria-label=\"{{ item.badge }}
|
|
9031
|
+
"template": "<mat-sidenav-container [class]=\"containerClasses()\" [hasBackdrop]=\"hasBackdrop()\">\n <mat-sidenav\n [class]=\"sidenavClasses()\"\n [mode]=\"mode()\"\n [position]=\"position()\"\n [opened]=\"opened()\"\n [style.width]=\"sidenavWidth()\"\n (openedChange)=\"mfOpenedChange.emit($event)\"\n >\n @if (navItems().length > 0) {\n <div class=\"mf-sidenav__nav\">\n @if (headerTitle()) {\n <div class=\"mf-sidenav__header\">\n @if (headerIcon()) {\n <mat-icon class=\"mf-sidenav__header-icon\" aria-hidden=\"true\">{{ headerIcon() }}</mat-icon>\n }\n <span class=\"mf-sidenav__header-title\">{{ headerTitle() }}</span>\n </div>\n }\n <nav class=\"mf-sidenav__menu\" [attr.aria-label]=\"navAriaLabel()\">\n @for (item of navItems(); track item.id) {\n <button\n type=\"button\"\n class=\"mf-sidenav__item\"\n [class.mf-sidenav__item--active]=\"item.active\"\n [class.mf-sidenav__item--disabled]=\"item.disabled\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-current]=\"item.active ? 'page' : null\"\n (click)=\"!item.disabled && mfNavItemClick.emit(item)\"\n >\n <mat-icon class=\"mf-sidenav__item-icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"mf-sidenav__item-label\">{{ item.label }}</span>\n @if (item.badge && item.badge > 0) {\n <span class=\"mf-sidenav__item-badge\" aria-label=\"{{ item.badge }} notifications\">\n {{ item.badge > 99 ? '99+' : item.badge }}\n </span>\n }\n </button>\n }\n </nav>\n </div>\n } @else {\n <ng-content select=\"[mfSidenavContent]\" />\n }\n </mat-sidenav>\n <mat-sidenav-content class=\"mf-sidenav__main\">\n <ng-content />\n </mat-sidenav-content>\n</mat-sidenav-container>\n",
|
|
9032
9032
|
"templateUrl": [],
|
|
9033
9033
|
"viewProviders": [],
|
|
9034
9034
|
"hostDirectives": [],
|
|
@@ -9099,7 +9099,7 @@
|
|
|
9099
9099
|
},
|
|
9100
9100
|
{
|
|
9101
9101
|
"name": "navAriaLabel",
|
|
9102
|
-
"defaultValue": "'
|
|
9102
|
+
"defaultValue": "'Primary navigation'",
|
|
9103
9103
|
"deprecated": false,
|
|
9104
9104
|
"deprecationMessage": "",
|
|
9105
9105
|
"indexKey": "",
|
|
@@ -9255,7 +9255,7 @@
|
|
|
9255
9255
|
"description": "<p>Panel lateral de la librería ng-comps.\nEnvuelve Angular Material <code>mat-sidenav-container</code> y expone una API uniforme\ncon look and feel de marca.</p>\n<p>Dos formas de uso:</p>\n<ol>\n<li><strong>Navitems declarativos</strong> — Proporciona <code>navItems</code>, <code>headerTitle</code> e icono.</li>\n<li><strong>Content projection</strong> — Proyecta <code>[mfSidenavContent]</code> para control total.</li>\n</ol>\n<p>El contenido principal se proyecta sin atributo.</p>\n",
|
|
9256
9256
|
"rawdescription": "\n\nPanel lateral de la librería ng-comps.\nEnvuelve Angular Material `mat-sidenav-container` y expone una API uniforme\ncon look and feel de marca.\n\nDos formas de uso:\n1. **Navitems declarativos** — Proporciona `navItems`, `headerTitle` e icono.\n2. **Content projection** — Proyecta `[mfSidenavContent]` para control total.\n\nEl contenido principal se proyecta sin atributo.\n",
|
|
9257
9257
|
"type": "component",
|
|
9258
|
-
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatSidenavModule } from '@angular/material/sidenav';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfSidenavMode = 'over' | 'push' | 'side';\r\nexport type MfSidenavPosition = 'start' | 'end';\r\n\r\nexport interface MfSidenavNavItem {\r\n /** Nombre del icono Material (e.g. 'home', 'dashboard') */\r\n icon: string;\r\n /** Texto de la etiqueta */\r\n label: string;\r\n /** Identificador único del ítem */\r\n id: string;\r\n /** Ítem activo/seleccionado */\r\n active?: boolean;\r\n /** Deshabilitar el ítem */\r\n disabled?: boolean;\r\n /** Número de badge (0 oculta el badge) */\r\n badge?: number;\r\n}\r\n\r\n/**\r\n * Panel lateral de la librería ng-comps.\r\n * Envuelve Angular Material `mat-sidenav-container` y expone una API uniforme\r\n * con look and feel de marca.\r\n *\r\n * Dos formas de uso:\r\n * 1. **Navitems declarativos** — Proporciona `navItems`, `headerTitle` e icono.\r\n * 2. **Content projection** — Proyecta `[mfSidenavContent]` para control total.\r\n *\r\n * El contenido principal se proyecta sin atributo.\r\n */\r\n@Component({\r\n selector: 'mf-sidenav',\r\n imports: [MatSidenavModule, MatIconModule],\r\n template: `\r\n <mat-sidenav-container [class]=\"containerClasses()\" [hasBackdrop]=\"hasBackdrop()\">\r\n <mat-sidenav\r\n [class]=\"sidenavClasses()\"\r\n [mode]=\"mode()\"\r\n [position]=\"position()\"\r\n [opened]=\"opened()\"\r\n [style.width]=\"sidenavWidth()\"\r\n (openedChange)=\"mfOpenedChange.emit($event)\"\r\n >\r\n @if (navItems().length > 0) {\r\n <div class=\"mf-sidenav__nav\">\r\n @if (headerTitle()) {\r\n <div class=\"mf-sidenav__header\">\r\n @if (headerIcon()) {\r\n <mat-icon class=\"mf-sidenav__header-icon\" aria-hidden=\"true\">{{ headerIcon() }}</mat-icon>\r\n }\r\n <span class=\"mf-sidenav__header-title\">{{ headerTitle() }}</span>\r\n </div>\r\n }\r\n <nav class=\"mf-sidenav__menu\" [attr.aria-label]=\"navAriaLabel()\">\r\n @for (item of navItems(); track item.id) {\r\n <button\r\n type=\"button\"\r\n class=\"mf-sidenav__item\"\r\n [class.mf-sidenav__item--active]=\"item.active\"\r\n [class.mf-sidenav__item--disabled]=\"item.disabled\"\r\n [disabled]=\"item.disabled ?? false\"\r\n [attr.aria-current]=\"item.active ? 'page' : null\"\r\n (click)=\"!item.disabled && mfNavItemClick.emit(item)\"\r\n >\r\n <mat-icon class=\"mf-sidenav__item-icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n <span class=\"mf-sidenav__item-label\">{{ item.label }}</span>\r\n @if (item.badge && item.badge > 0) {\r\n <span class=\"mf-sidenav__item-badge\" aria-label=\"{{ item.badge }}
|
|
9258
|
+
"sourceCode": "import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { MatSidenavModule } from '@angular/material/sidenav';\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\nexport type MfSidenavMode = 'over' | 'push' | 'side';\r\nexport type MfSidenavPosition = 'start' | 'end';\r\n\r\nexport interface MfSidenavNavItem {\r\n /** Nombre del icono Material (e.g. 'home', 'dashboard') */\r\n icon: string;\r\n /** Texto de la etiqueta */\r\n label: string;\r\n /** Identificador único del ítem */\r\n id: string;\r\n /** Ítem activo/seleccionado */\r\n active?: boolean;\r\n /** Deshabilitar el ítem */\r\n disabled?: boolean;\r\n /** Número de badge (0 oculta el badge) */\r\n badge?: number;\r\n}\r\n\r\n/**\r\n * Panel lateral de la librería ng-comps.\r\n * Envuelve Angular Material `mat-sidenav-container` y expone una API uniforme\r\n * con look and feel de marca.\r\n *\r\n * Dos formas de uso:\r\n * 1. **Navitems declarativos** — Proporciona `navItems`, `headerTitle` e icono.\r\n * 2. **Content projection** — Proyecta `[mfSidenavContent]` para control total.\r\n *\r\n * El contenido principal se proyecta sin atributo.\r\n */\r\n@Component({\r\n selector: 'mf-sidenav',\r\n imports: [MatSidenavModule, MatIconModule],\r\n template: `\r\n <mat-sidenav-container [class]=\"containerClasses()\" [hasBackdrop]=\"hasBackdrop()\">\r\n <mat-sidenav\r\n [class]=\"sidenavClasses()\"\r\n [mode]=\"mode()\"\r\n [position]=\"position()\"\r\n [opened]=\"opened()\"\r\n [style.width]=\"sidenavWidth()\"\r\n (openedChange)=\"mfOpenedChange.emit($event)\"\r\n >\r\n @if (navItems().length > 0) {\r\n <div class=\"mf-sidenav__nav\">\r\n @if (headerTitle()) {\r\n <div class=\"mf-sidenav__header\">\r\n @if (headerIcon()) {\r\n <mat-icon class=\"mf-sidenav__header-icon\" aria-hidden=\"true\">{{ headerIcon() }}</mat-icon>\r\n }\r\n <span class=\"mf-sidenav__header-title\">{{ headerTitle() }}</span>\r\n </div>\r\n }\r\n <nav class=\"mf-sidenav__menu\" [attr.aria-label]=\"navAriaLabel()\">\r\n @for (item of navItems(); track item.id) {\r\n <button\r\n type=\"button\"\r\n class=\"mf-sidenav__item\"\r\n [class.mf-sidenav__item--active]=\"item.active\"\r\n [class.mf-sidenav__item--disabled]=\"item.disabled\"\r\n [disabled]=\"item.disabled ?? false\"\r\n [attr.aria-current]=\"item.active ? 'page' : null\"\r\n (click)=\"!item.disabled && mfNavItemClick.emit(item)\"\r\n >\r\n <mat-icon class=\"mf-sidenav__item-icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\r\n <span class=\"mf-sidenav__item-label\">{{ item.label }}</span>\r\n @if (item.badge && item.badge > 0) {\r\n <span class=\"mf-sidenav__item-badge\" aria-label=\"{{ item.badge }} notifications\">\n {{ item.badge > 99 ? '99+' : item.badge }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </nav>\r\n </div>\r\n } @else {\r\n <ng-content select=\"[mfSidenavContent]\" />\r\n }\r\n </mat-sidenav>\r\n <mat-sidenav-content class=\"mf-sidenav__main\">\r\n <ng-content />\r\n </mat-sidenav-content>\r\n </mat-sidenav-container>\r\n `,\r\n styleUrl: './mf-sidenav.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class MfSidenavComponent {\r\n /** Abierto o cerrado */\r\n readonly opened = input(false);\r\n /** Modo de apertura */\r\n readonly mode = input<MfSidenavMode>('side');\r\n /** Posición del panel */\r\n readonly position = input<MfSidenavPosition>('start');\r\n /** Muestra backdrop al abrir */\r\n readonly hasBackdrop = input<boolean | null>(null);\r\n /** Ancho del panel lateral */\r\n readonly sidenavWidth = input('260px');\r\n /** Ítems de navegación declarativos */\r\n readonly navItems = input<MfSidenavNavItem[]>([]);\r\n /** Título de la cabecera del sidenav */\r\n readonly headerTitle = input<string | undefined>(undefined);\r\n /** Icono Material de la cabecera */\r\n readonly headerIcon = input<string | undefined>(undefined);\r\n /** Aria-label del elemento nav */\r\n readonly navAriaLabel = input('Primary navigation');\n\r\n readonly mfOpenedChange = output<boolean>();\r\n /** Emite el ítem de navegación pulsado */\r\n readonly mfNavItemClick = output<MfSidenavNavItem>();\r\n\r\n readonly containerClasses = computed(() => 'mf-sidenav-container');\r\n\r\n readonly sidenavClasses = computed(() => {\r\n return `mf-sidenav mf-sidenav--${this.mode()}`;\r\n });\r\n}\r\n",
|
|
9259
9259
|
"styleUrl": "./mf-sidenav.component.css",
|
|
9260
9260
|
"assetsDirs": [],
|
|
9261
9261
|
"styleUrlsData": "",
|
|
@@ -9931,7 +9931,7 @@
|
|
|
9931
9931
|
},
|
|
9932
9932
|
{
|
|
9933
9933
|
"name": "MfTableComponent",
|
|
9934
|
-
"id": "component-MfTableComponent-
|
|
9934
|
+
"id": "component-MfTableComponent-6369889e22ebd32d501cc29b2a48c86342cf5122bc6a7b5fb94a8c5cc889322854baedf9b1fbf52341440e0aad32cfe087081a9a49f2693ba78edd481bec963c",
|
|
9935
9935
|
"file": "src/app/components/table/mf-table.component.ts",
|
|
9936
9936
|
"changeDetection": "ChangeDetectionStrategy.OnPush",
|
|
9937
9937
|
"encapsulation": [],
|
|
@@ -9979,7 +9979,7 @@
|
|
|
9979
9979
|
},
|
|
9980
9980
|
{
|
|
9981
9981
|
"name": "rowActionHeader",
|
|
9982
|
-
"defaultValue": "'
|
|
9982
|
+
"defaultValue": "'Actions'",
|
|
9983
9983
|
"deprecated": false,
|
|
9984
9984
|
"deprecationMessage": "",
|
|
9985
9985
|
"indexKey": "",
|
|
@@ -10055,16 +10055,16 @@
|
|
|
10055
10055
|
],
|
|
10056
10056
|
"jsdoctags": [
|
|
10057
10057
|
{
|
|
10058
|
-
"pos":
|
|
10059
|
-
"end":
|
|
10058
|
+
"pos": 3175,
|
|
10059
|
+
"end": 3245,
|
|
10060
10060
|
"kind": 332,
|
|
10061
10061
|
"id": 0,
|
|
10062
10062
|
"flags": 16842752,
|
|
10063
10063
|
"modifierFlagsCache": 0,
|
|
10064
10064
|
"transformFlags": 0,
|
|
10065
10065
|
"tagName": {
|
|
10066
|
-
"pos":
|
|
10067
|
-
"end":
|
|
10066
|
+
"pos": 3176,
|
|
10067
|
+
"end": 3186,
|
|
10068
10068
|
"kind": 80,
|
|
10069
10069
|
"id": 0,
|
|
10070
10070
|
"flags": 16842752,
|
|
@@ -10242,7 +10242,7 @@
|
|
|
10242
10242
|
"description": "<p>Table de la librerÃa ng-comps.\nEnvuelve Angular Material <code>mat-table</code> y expone una API uniforme\ncon look and feel de marca. Ideal para dashboards y paneles de datos.</p>\n",
|
|
10243
10243
|
"rawdescription": "\n\nTable de la librerÃa ng-comps.\nEnvuelve Angular Material `mat-table` y expone una API uniforme\ncon look and feel de marca. Ideal para dashboards y paneles de datos.\n",
|
|
10244
10244
|
"type": "component",
|
|
10245
|
-
"sourceCode": "import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n} from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatTableModule } from '@angular/material/table';\n\nexport interface MfTableColumn {\n key: string;\n header: string;\n sortable?: boolean;\n}\n\nexport type MfTableVariant = 'default' | 'striped' | 'bordered';\n\n/**\n * Table de la librerÃa ng-comps.\n * Envuelve Angular Material `mat-table` y expone una API uniforme\n * con look and feel de marca. Ideal para dashboards y paneles de datos.\n */\n@Component({\n selector: 'mf-table',\n imports: [MatTableModule, MatSortModule, MatButtonModule, MatIconModule],\n template: `\n <div class=\"mf-table__wrapper\" [class]=\"hostClasses()\">\n <table\n mat-table\n [dataSource]=\"data()\"\n matSort\n (matSortChange)=\"mfSortChange.emit($event)\"\n >\n @for (col of columns(); track col.key) {\n <ng-container [matColumnDef]=\"col.key\">\n @if (col.sortable) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header>{{ col.header }}</th>\n } @else {\n <th mat-header-cell *matHeaderCellDef>{{ col.header }}</th>\n }\n <td mat-cell *matCellDef=\"let row\">{{ row[col.key] }}</td>\n </ng-container>\n }\n\n @if (rowActionLabel()) {\n <ng-container [matColumnDef]=\"actionColumnKey\">\n <th mat-header-cell *matHeaderCellDef class=\"mf-table__actions-header\">\n {{ rowActionHeader() }}\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mf-table__actions-cell\">\n <button\n mat-button\n type=\"button\"\n class=\"mf-table__action\"\n [attr.aria-label]=\"getRowActionAriaLabel(row)\"\n (click)=\"emitRowAction(row)\"\n >\n {{ rowActionLabel() }}\n </button>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns()\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns()\"></tr>\n </table>\n </div>\n `,\n styleUrl: './mf-table.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfTableComponent {\n protected readonly actionColumnKey = 'mf-row-action';\n\n /** Columnas de la tabla */\n readonly columns = input.required<MfTableColumn[]>();\n /** Datos de la tabla */\n readonly data = input.required<Record<string, unknown>[]>();\n /** Variante visual */\n readonly variant = input<MfTableVariant>('default');\n /** Texto visible del botón de acción por fila */\n readonly rowActionLabel = input<string | undefined>(undefined);\n /** Cabecera visible de la columna de acción */\n readonly rowActionHeader = input('
|
|
10245
|
+
"sourceCode": "import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n} from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatTableModule } from '@angular/material/table';\n\nexport interface MfTableColumn {\n key: string;\n header: string;\n sortable?: boolean;\n}\n\nexport type MfTableVariant = 'default' | 'striped' | 'bordered';\n\n/**\n * Table de la librerÃa ng-comps.\n * Envuelve Angular Material `mat-table` y expone una API uniforme\n * con look and feel de marca. Ideal para dashboards y paneles de datos.\n */\n@Component({\n selector: 'mf-table',\n imports: [MatTableModule, MatSortModule, MatButtonModule, MatIconModule],\n template: `\n <div class=\"mf-table__wrapper\" [class]=\"hostClasses()\">\n <table\n mat-table\n [dataSource]=\"data()\"\n matSort\n (matSortChange)=\"mfSortChange.emit($event)\"\n >\n @for (col of columns(); track col.key) {\n <ng-container [matColumnDef]=\"col.key\">\n @if (col.sortable) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header>{{ col.header }}</th>\n } @else {\n <th mat-header-cell *matHeaderCellDef>{{ col.header }}</th>\n }\n <td mat-cell *matCellDef=\"let row\">{{ row[col.key] }}</td>\n </ng-container>\n }\n\n @if (rowActionLabel()) {\n <ng-container [matColumnDef]=\"actionColumnKey\">\n <th mat-header-cell *matHeaderCellDef class=\"mf-table__actions-header\">\n {{ rowActionHeader() }}\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mf-table__actions-cell\">\n <button\n mat-button\n type=\"button\"\n class=\"mf-table__action\"\n [attr.aria-label]=\"getRowActionAriaLabel(row)\"\n (click)=\"emitRowAction(row)\"\n >\n {{ rowActionLabel() }}\n </button>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns()\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns()\"></tr>\n </table>\n </div>\n `,\n styleUrl: './mf-table.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MfTableComponent {\n protected readonly actionColumnKey = 'mf-row-action';\n\n /** Columnas de la tabla */\n readonly columns = input.required<MfTableColumn[]>();\n /** Datos de la tabla */\n readonly data = input.required<Record<string, unknown>[]>();\n /** Variante visual */\n readonly variant = input<MfTableVariant>('default');\n /** Texto visible del botón de acción por fila */\n readonly rowActionLabel = input<string | undefined>(undefined);\n /** Cabecera visible de la columna de acción */\n readonly rowActionHeader = input('Actions');\n readonly rowActionAriaLabel = input<\n ((row: Record<string, unknown>) => string) | undefined\n >(undefined);\n\n readonly mfSortChange = output<Sort>();\n readonly mfRowAction = output<Record<string, unknown>>();\n /** @deprecated usa `mfRowAction` para interacciones explÃcitas por fila */\n readonly mfRowClick = output<Record<string, unknown>>();\n\n readonly displayedColumns = computed(() => {\n const columns = this.columns().map((column) => column.key);\n if (this.rowActionLabel()) {\n columns.push(this.actionColumnKey);\n }\n return columns;\n });\n\n readonly hostClasses = computed(() => {\n return ['mf-table', `mf-table--${this.variant()}`].join(' ');\n });\n\n emitRowAction(row: Record<string, unknown>): void {\n this.mfRowAction.emit(row);\n this.mfRowClick.emit(row);\n }\n\n getRowActionAriaLabel(row: Record<string, unknown>): string | null {\n return this.rowActionAriaLabel()?.(row) ?? this.rowActionLabel() ?? null;\n }\n}\n",
|
|
10246
10246
|
"styleUrl": "./mf-table.component.css",
|
|
10247
10247
|
"assetsDirs": [],
|
|
10248
10248
|
"styleUrlsData": "",
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, rmSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
3
|
|
|
4
4
|
const root = process.cwd();
|
|
5
5
|
const rootPkgPath = resolve(root, 'package.json');
|
|
@@ -12,26 +12,45 @@ if (!existsSync(distDir)) {
|
|
|
12
12
|
|
|
13
13
|
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf8'));
|
|
14
14
|
const angularVersion = rootPkg.dependencies['@angular/core'];
|
|
15
|
-
const cdkVersion = rootPkg.dependencies['@angular/cdk'];
|
|
16
|
-
const materialVersion = rootPkg.dependencies['@angular/material'];
|
|
17
|
-
const rxjsVersion = rootPkg.dependencies.rxjs;
|
|
18
|
-
const tslibVersion = rootPkg.dependencies.tslib;
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
const cdkVersion = rootPkg.dependencies['@angular/cdk'];
|
|
16
|
+
const materialVersion = rootPkg.dependencies['@angular/material'];
|
|
17
|
+
const rxjsVersion = rootPkg.dependencies.rxjs;
|
|
18
|
+
const tslibVersion = rootPkg.dependencies.tslib;
|
|
19
|
+
|
|
20
|
+
for (const extraPath of [
|
|
21
|
+
resolve(distDir, 'browser'),
|
|
22
|
+
resolve(distDir, '3rdpartylicenses.txt'),
|
|
23
|
+
resolve(distDir, 'prerendered-routes.json')
|
|
24
|
+
]) {
|
|
25
|
+
if (existsSync(extraPath)) {
|
|
26
|
+
rmSync(extraPath, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const packageJson = {
|
|
31
|
+
name: rootPkg.name,
|
|
32
|
+
version: rootPkg.version,
|
|
33
|
+
description: 'Angular UI components for mf-design-system',
|
|
24
34
|
keywords: ['angular', 'components', 'ui', 'design-system', 'material'],
|
|
25
35
|
license: rootPkg.license || 'MIT',
|
|
26
36
|
type: 'module',
|
|
27
|
-
sideEffects: false,
|
|
28
|
-
main: './fesm2022/ng-comps.mjs',
|
|
29
|
-
module: './fesm2022/ng-comps.mjs',
|
|
30
|
-
typings: './types/ng-comps.d.ts',
|
|
31
|
-
|
|
32
|
-
'.'
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
sideEffects: false,
|
|
38
|
+
main: './fesm2022/ng-comps.mjs',
|
|
39
|
+
module: './fesm2022/ng-comps.mjs',
|
|
40
|
+
typings: './types/ng-comps.d.ts',
|
|
41
|
+
files: [
|
|
42
|
+
'fesm2022/ng-comps.mjs',
|
|
43
|
+
'types/ng-comps.d.ts',
|
|
44
|
+
'src/styles.css',
|
|
45
|
+
'src/theme',
|
|
46
|
+
'README.md',
|
|
47
|
+
'LICENSE',
|
|
48
|
+
'package.json'
|
|
49
|
+
],
|
|
50
|
+
exports: {
|
|
51
|
+
'.': {
|
|
52
|
+
types: './types/ng-comps.d.ts',
|
|
53
|
+
default: './fesm2022/ng-comps.mjs'
|
|
35
54
|
},
|
|
36
55
|
'./styles.css': './src/styles.css',
|
|
37
56
|
'./theme/tokens.css': './src/theme/tokens.css',
|
|
@@ -39,10 +39,10 @@ describe('MfAlertComponent', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('should show title when provided', () => {
|
|
42
|
-
fixture.componentRef.setInput('title', '
|
|
42
|
+
fixture.componentRef.setInput('title', 'Attention');
|
|
43
43
|
fixture.detectChanges();
|
|
44
44
|
const title = fixture.nativeElement.querySelector('.mf-alert__title');
|
|
45
|
-
expect(title?.textContent).toContain('
|
|
45
|
+
expect(title?.textContent).toContain('Attention');
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
it('should show close button when dismissible', () => {
|
|
@@ -30,7 +30,7 @@ export type MfAlertSeverity = 'info' | 'success' | 'warning' | 'error';
|
|
|
30
30
|
<button
|
|
31
31
|
class="mf-alert__close"
|
|
32
32
|
(click)="mfDismiss.emit()"
|
|
33
|
-
[attr.aria-label]="'
|
|
33
|
+
[attr.aria-label]="'Close alert'"
|
|
34
34
|
>
|
|
35
35
|
<mat-icon aria-hidden="true">close</mat-icon>
|
|
36
36
|
</button>
|