ng-comps 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/fesm2022/ng-comps.mjs +4254 -0
  2. package/package.json +54 -58
  3. package/src/styles.css +54 -0
  4. package/types/ng-comps.d.ts +1348 -0
  5. package/.editorconfig +0 -17
  6. package/.github/copilot-instructions.md +0 -55
  7. package/.github/workflows/ci.yml +0 -29
  8. package/.prettierrc +0 -12
  9. package/.storybook/main.ts +0 -21
  10. package/.storybook/preview.ts +0 -27
  11. package/.storybook/tsconfig.doc.json +0 -10
  12. package/.storybook/tsconfig.json +0 -15
  13. package/.storybook/typings.d.ts +0 -4
  14. package/.vscode/extensions.json +0 -4
  15. package/.vscode/launch.json +0 -20
  16. package/.vscode/mcp.json +0 -9
  17. package/.vscode/tasks.json +0 -42
  18. package/ACCESSIBILITY.md +0 -127
  19. package/angular.json +0 -106
  20. package/documentation.json +0 -13394
  21. package/ng-package.json +0 -27
  22. package/public/favicon.ico +0 -0
  23. package/scripts/prepare-package.mjs +0 -80
  24. package/src/app/a11y/accessibility.utils.ts +0 -35
  25. package/src/app/a11y/index.ts +0 -6
  26. package/src/app/accessibility/ng-comps.a11y.spec.ts +0 -108
  27. package/src/app/app.config.ts +0 -11
  28. package/src/app/app.css +0 -107
  29. package/src/app/app.html +0 -48
  30. package/src/app/app.routes.ts +0 -3
  31. package/src/app/app.spec.ts +0 -23
  32. package/src/app/app.ts +0 -10
  33. package/src/app/components/accordion/index.ts +0 -2
  34. package/src/app/components/accordion/mf-accordion.component.css +0 -38
  35. package/src/app/components/accordion/mf-accordion.component.spec.ts +0 -48
  36. package/src/app/components/accordion/mf-accordion.component.ts +0 -53
  37. package/src/app/components/alert/index.ts +0 -2
  38. package/src/app/components/alert/mf-alert.component.css +0 -100
  39. package/src/app/components/alert/mf-alert.component.spec.ts +0 -59
  40. package/src/app/components/alert/mf-alert.component.ts +0 -68
  41. package/src/app/components/autocomplete/index.ts +0 -5
  42. package/src/app/components/autocomplete/mf-autocomplete.component.css +0 -105
  43. package/src/app/components/autocomplete/mf-autocomplete.component.spec.ts +0 -116
  44. package/src/app/components/autocomplete/mf-autocomplete.component.ts +0 -307
  45. package/src/app/components/avatar/index.ts +0 -2
  46. package/src/app/components/avatar/mf-avatar.component.css +0 -27
  47. package/src/app/components/avatar/mf-avatar.component.spec.ts +0 -49
  48. package/src/app/components/avatar/mf-avatar.component.ts +0 -99
  49. package/src/app/components/badge/index.ts +0 -2
  50. package/src/app/components/badge/mf-badge.component.css +0 -32
  51. package/src/app/components/badge/mf-badge.component.spec.ts +0 -40
  52. package/src/app/components/badge/mf-badge.component.ts +0 -105
  53. package/src/app/components/breadcrumb/index.ts +0 -2
  54. package/src/app/components/breadcrumb/mf-breadcrumb.component.css +0 -61
  55. package/src/app/components/breadcrumb/mf-breadcrumb.component.spec.ts +0 -61
  56. package/src/app/components/breadcrumb/mf-breadcrumb.component.ts +0 -75
  57. package/src/app/components/button/index.ts +0 -2
  58. package/src/app/components/button/mf-button.component.css +0 -136
  59. package/src/app/components/button/mf-button.component.ts +0 -174
  60. package/src/app/components/card/index.ts +0 -2
  61. package/src/app/components/card/mf-card.component.css +0 -82
  62. package/src/app/components/card/mf-card.component.ts +0 -59
  63. package/src/app/components/checkbox/index.ts +0 -1
  64. package/src/app/components/checkbox/mf-checkbox.component.css +0 -75
  65. package/src/app/components/checkbox/mf-checkbox.component.ts +0 -187
  66. package/src/app/components/chip/index.ts +0 -2
  67. package/src/app/components/chip/mf-chip.component.css +0 -69
  68. package/src/app/components/chip/mf-chip.component.spec.ts +0 -47
  69. package/src/app/components/chip/mf-chip.component.ts +0 -77
  70. package/src/app/components/datepicker/index.ts +0 -2
  71. package/src/app/components/datepicker/mf-datepicker.component.css +0 -102
  72. package/src/app/components/datepicker/mf-datepicker.component.spec.ts +0 -69
  73. package/src/app/components/datepicker/mf-datepicker.component.ts +0 -233
  74. package/src/app/components/dialog/index.ts +0 -3
  75. package/src/app/components/dialog/mf-dialog.component.css +0 -73
  76. package/src/app/components/dialog/mf-dialog.component.ts +0 -160
  77. package/src/app/components/dialog/mf-dialog.service.spec.ts +0 -61
  78. package/src/app/components/dialog/mf-dialog.service.ts +0 -52
  79. package/src/app/components/divider/index.ts +0 -2
  80. package/src/app/components/divider/mf-divider.component.css +0 -38
  81. package/src/app/components/divider/mf-divider.component.spec.ts +0 -40
  82. package/src/app/components/divider/mf-divider.component.ts +0 -44
  83. package/src/app/components/form-field/index.ts +0 -1
  84. package/src/app/components/form-field/mf-form-field.component.css +0 -51
  85. package/src/app/components/form-field/mf-form-field.component.ts +0 -74
  86. package/src/app/components/grid-list/index.ts +0 -2
  87. package/src/app/components/grid-list/mf-grid-list.component.css +0 -47
  88. package/src/app/components/grid-list/mf-grid-list.component.spec.ts +0 -57
  89. package/src/app/components/grid-list/mf-grid-list.component.ts +0 -68
  90. package/src/app/components/icon/index.ts +0 -2
  91. package/src/app/components/icon/mf-icon.component.css +0 -56
  92. package/src/app/components/icon/mf-icon.component.ts +0 -41
  93. package/src/app/components/input/index.ts +0 -2
  94. package/src/app/components/input/mf-input.component.css +0 -105
  95. package/src/app/components/input/mf-input.component.ts +0 -217
  96. package/src/app/components/menu/index.ts +0 -2
  97. package/src/app/components/menu/mf-menu.component.css +0 -31
  98. package/src/app/components/menu/mf-menu.component.spec.ts +0 -49
  99. package/src/app/components/menu/mf-menu.component.ts +0 -66
  100. package/src/app/components/paginator/index.ts +0 -1
  101. package/src/app/components/paginator/mf-paginator.component.css +0 -32
  102. package/src/app/components/paginator/mf-paginator.component.spec.ts +0 -44
  103. package/src/app/components/paginator/mf-paginator.component.ts +0 -52
  104. package/src/app/components/progress-bar/index.ts +0 -2
  105. package/src/app/components/progress-bar/mf-progress-bar.component.css +0 -53
  106. package/src/app/components/progress-bar/mf-progress-bar.component.spec.ts +0 -65
  107. package/src/app/components/progress-bar/mf-progress-bar.component.ts +0 -79
  108. package/src/app/components/progress-spinner/index.ts +0 -2
  109. package/src/app/components/progress-spinner/mf-progress-spinner.component.css +0 -38
  110. package/src/app/components/progress-spinner/mf-progress-spinner.component.spec.ts +0 -59
  111. package/src/app/components/progress-spinner/mf-progress-spinner.component.ts +0 -81
  112. package/src/app/components/radio-button/index.ts +0 -2
  113. package/src/app/components/radio-button/mf-radio-button.component.css +0 -86
  114. package/src/app/components/radio-button/mf-radio-button.component.spec.ts +0 -55
  115. package/src/app/components/radio-button/mf-radio-button.component.ts +0 -219
  116. package/src/app/components/select/index.ts +0 -2
  117. package/src/app/components/select/mf-select.component.css +0 -121
  118. package/src/app/components/select/mf-select.component.spec.ts +0 -108
  119. package/src/app/components/select/mf-select.component.ts +0 -252
  120. package/src/app/components/sidenav/index.ts +0 -2
  121. package/src/app/components/sidenav/mf-sidenav.component.css +0 -168
  122. package/src/app/components/sidenav/mf-sidenav.component.spec.ts +0 -57
  123. package/src/app/components/sidenav/mf-sidenav.component.ts +0 -126
  124. package/src/app/components/slide-toggle/index.ts +0 -1
  125. package/src/app/components/slide-toggle/mf-slide-toggle.component.css +0 -42
  126. package/src/app/components/slide-toggle/mf-slide-toggle.component.spec.ts +0 -43
  127. package/src/app/components/slide-toggle/mf-slide-toggle.component.ts +0 -188
  128. package/src/app/components/snackbar/index.ts +0 -2
  129. package/src/app/components/snackbar/mf-snackbar.service.css +0 -31
  130. package/src/app/components/snackbar/mf-snackbar.service.spec.ts +0 -81
  131. package/src/app/components/snackbar/mf-snackbar.service.ts +0 -77
  132. package/src/app/components/table/index.ts +0 -2
  133. package/src/app/components/table/mf-table.component.css +0 -68
  134. package/src/app/components/table/mf-table.component.spec.ts +0 -76
  135. package/src/app/components/table/mf-table.component.ts +0 -117
  136. package/src/app/components/tabs/index.ts +0 -2
  137. package/src/app/components/tabs/mf-tabs.component.css +0 -31
  138. package/src/app/components/tabs/mf-tabs.component.spec.ts +0 -50
  139. package/src/app/components/tabs/mf-tabs.component.ts +0 -62
  140. package/src/app/components/textarea/index.ts +0 -2
  141. package/src/app/components/textarea/mf-textarea.component.css +0 -48
  142. package/src/app/components/textarea/mf-textarea.component.spec.ts +0 -55
  143. package/src/app/components/textarea/mf-textarea.component.ts +0 -227
  144. package/src/app/components/toolbar/index.ts +0 -2
  145. package/src/app/components/toolbar/mf-toolbar.component.css +0 -77
  146. package/src/app/components/toolbar/mf-toolbar.component.ts +0 -56
  147. package/src/app/components/tooltip/index.ts +0 -3
  148. package/src/app/components/tooltip/mf-tooltip.component.css +0 -7
  149. package/src/app/components/tooltip/mf-tooltip.component.spec.ts +0 -37
  150. package/src/app/components/tooltip/mf-tooltip.component.ts +0 -47
  151. package/src/app/components/tooltip/mf-tooltip.directive.ts +0 -22
  152. package/src/index.html +0 -18
  153. package/src/main.ts +0 -6
  154. package/src/public-api.ts +0 -31
  155. package/src/stories/About.mdx +0 -72
  156. package/src/stories/Accessibility.mdx +0 -59
  157. package/src/stories/Welcome.mdx +0 -26
  158. package/src/stories/assets/accessibility.png +0 -0
  159. package/src/stories/assets/accessibility.svg +0 -1
  160. package/src/stories/assets/addon-library.png +0 -0
  161. package/src/stories/assets/assets.png +0 -0
  162. package/src/stories/assets/avif-test-image.avif +0 -0
  163. package/src/stories/assets/context.png +0 -0
  164. package/src/stories/assets/discord.svg +0 -1
  165. package/src/stories/assets/docs.png +0 -0
  166. package/src/stories/assets/figma-plugin.png +0 -0
  167. package/src/stories/assets/github.svg +0 -1
  168. package/src/stories/assets/share.png +0 -0
  169. package/src/stories/assets/styling.png +0 -0
  170. package/src/stories/assets/testing.png +0 -0
  171. package/src/stories/assets/theming.png +0 -0
  172. package/src/stories/assets/tutorials.svg +0 -1
  173. package/src/stories/assets/youtube.svg +0 -1
  174. package/src/stories/mf-a11y-contracts.stories.ts +0 -472
  175. package/src/stories/mf-autocomplete.stories.ts +0 -194
  176. package/src/stories/mf-button.stories.ts +0 -152
  177. package/src/stories/mf-card.stories.ts +0 -147
  178. package/src/stories/mf-checkbox.stories.ts +0 -88
  179. package/src/stories/mf-datepicker.stories.ts +0 -118
  180. package/src/stories/mf-dialog.stories.ts +0 -159
  181. package/src/stories/mf-form-field.stories.ts +0 -108
  182. package/src/stories/mf-grid-list.stories.ts +0 -104
  183. package/src/stories/mf-icon.stories.ts +0 -133
  184. package/src/stories/mf-input.stories.ts +0 -158
  185. package/src/stories/mf-menu.stories.ts +0 -71
  186. package/src/stories/mf-progress-bar.stories.ts +0 -119
  187. package/src/stories/mf-progress-spinner.stories.ts +0 -124
  188. package/src/stories/mf-radio-button.stories.ts +0 -111
  189. package/src/stories/mf-select.stories.ts +0 -184
  190. package/src/stories/mf-sidenav.stories.ts +0 -331
  191. package/src/stories/mf-table.stories.ts +0 -80
  192. package/src/stories/mf-toolbar.stories.ts +0 -112
  193. package/src/stories/user.ts +0 -3
  194. package/tsconfig.app.json +0 -15
  195. package/tsconfig.json +0 -33
  196. package/tsconfig.spec.json +0 -15
  197. package/vercel.json +0 -6
@@ -1,68 +0,0 @@
1
- :host {
2
- display: block;
3
- }
4
-
5
- .mf-table__wrapper {
6
- overflow-x: auto;
7
- border-radius: var(--mf-radius-md);
8
- border: 1px solid var(--mf-color-border);
9
- }
10
-
11
- .mf-table .mat-mdc-table {
12
- width: 100%;
13
- font-family: var(--mf-font-base) !important;
14
- }
15
-
16
- .mf-table .mat-mdc-header-cell {
17
- font-family: var(--mf-font-base) !important;
18
- font-weight: var(--mf-weight-bold) !important;
19
- font-size: var(--mf-text-sm) !important;
20
- color: var(--mf-color-neutral-600) !important;
21
- background-color: var(--mf-color-neutral-50) !important;
22
- border-bottom-color: var(--mf-color-border) !important;
23
- }
24
-
25
- .mf-table .mat-mdc-cell {
26
- font-family: var(--mf-font-base) !important;
27
- font-size: var(--mf-text-sm) !important;
28
- color: var(--mf-color-on-surface) !important;
29
- border-bottom-color: var(--mf-color-border) !important;
30
- }
31
-
32
- .mf-table .mat-mdc-row:hover {
33
- background-color: var(--mf-color-brand-light) !important;
34
- }
35
-
36
- /* ── Striped ──────────────────────────────────────────────────── */
37
- .mf-table--striped .mat-mdc-row:nth-child(even) {
38
- background-color: var(--mf-color-neutral-50);
39
- }
40
-
41
- /* ── Bordered ─────────────────────────────────────────────────── */
42
- .mf-table--bordered .mat-mdc-cell,
43
- .mf-table--bordered .mat-mdc-header-cell {
44
- border-right: 1px solid var(--mf-color-border) !important;
45
- }
46
-
47
- .mf-table--bordered .mat-mdc-cell:last-child,
48
- .mf-table--bordered .mat-mdc-header-cell:last-child {
49
- border-right: none !important;
50
- }
51
-
52
- /* ── Sort header ──────────────────────────────────────────────── */
53
- .mf-table .mat-sort-header-arrow {
54
- color: var(--mf-color-brand) !important;
55
- }
56
-
57
- .mf-table__actions-header,
58
- .mf-table__actions-cell {
59
- white-space: nowrap;
60
- width: 1%;
61
- }
62
-
63
- .mf-table__action {
64
- min-width: 0;
65
- font-family: var(--mf-font-base) !important;
66
- font-size: var(--mf-text-sm) !important;
67
- font-weight: var(--mf-weight-medium) !important;
68
- }
@@ -1,76 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
- import { MfTableComponent } from './mf-table.component';
3
- import { NoopAnimationsModule } from '@angular/platform-browser/animations';
4
-
5
- describe('MfTableComponent', () => {
6
- let fixture: ComponentFixture<MfTableComponent>;
7
- let component: MfTableComponent;
8
-
9
- const testColumns = [
10
- { key: 'name', header: 'Name' },
11
- { key: 'email', header: 'Email' },
12
- ];
13
-
14
- const testData = [
15
- { name: 'John', email: 'john@test.com' },
16
- { name: 'Jane', email: 'jane@test.com' },
17
- ];
18
-
19
- beforeEach(async () => {
20
- await TestBed.configureTestingModule({
21
- imports: [MfTableComponent, NoopAnimationsModule],
22
- }).compileComponents();
23
-
24
- fixture = TestBed.createComponent(MfTableComponent);
25
- component = fixture.componentInstance;
26
- fixture.componentRef.setInput('columns', testColumns);
27
- fixture.componentRef.setInput('data', testData);
28
- fixture.detectChanges();
29
- });
30
-
31
- it('should create', () => {
32
- expect(component).toBeTruthy();
33
- });
34
-
35
- it('should compute displayed columns', () => {
36
- expect(component.displayedColumns()).toEqual(['name', 'email']);
37
- });
38
-
39
- it('should render table', () => {
40
- const table = fixture.nativeElement.querySelector('table');
41
- expect(table).toBeTruthy();
42
- });
43
-
44
- it('should render header cells', () => {
45
- const headers = fixture.nativeElement.querySelectorAll('th');
46
- expect(headers.length).toBe(2);
47
- });
48
-
49
- it('should render data rows', () => {
50
- const rows = fixture.nativeElement.querySelectorAll('tr.mat-mdc-row');
51
- expect(rows.length).toBe(2);
52
- });
53
-
54
- it('should apply default variant', () => {
55
- expect(component.hostClasses()).toContain('mf-table--default');
56
- });
57
-
58
- it('should expose per-row aria labels for explicit actions', () => {
59
- fixture.componentRef.setInput('rowActionLabel', 'Ver detalle');
60
- fixture.componentRef.setInput(
61
- 'rowActionAriaLabel',
62
- (row: Record<string, unknown>) => `Ver detalle de ${row['name']}`,
63
- );
64
- fixture.detectChanges();
65
-
66
- const actionButtons =
67
- fixture.nativeElement.querySelectorAll('.mf-table__action');
68
-
69
- expect(actionButtons[0].getAttribute('aria-label')).toBe(
70
- 'Ver detalle de John',
71
- );
72
- expect(actionButtons[1].getAttribute('aria-label')).toBe(
73
- 'Ver detalle de Jane',
74
- );
75
- });
76
- });
@@ -1,117 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- output,
7
- } from '@angular/core';
8
- import { MatButtonModule } from '@angular/material/button';
9
- import { MatIconModule } from '@angular/material/icon';
10
- import { MatSortModule, Sort } from '@angular/material/sort';
11
- import { MatTableModule } from '@angular/material/table';
12
-
13
- export interface MfTableColumn {
14
- key: string;
15
- header: string;
16
- sortable?: boolean;
17
- }
18
-
19
- export type MfTableVariant = 'default' | 'striped' | 'bordered';
20
-
21
- /**
22
- * Table de la librería ng-comps.
23
- * Envuelve Angular Material `mat-table` y expone una API uniforme
24
- * con look and feel de marca. Ideal para dashboards y paneles de datos.
25
- */
26
- @Component({
27
- selector: 'mf-table',
28
- imports: [MatTableModule, MatSortModule, MatButtonModule, MatIconModule],
29
- template: `
30
- <div class="mf-table__wrapper" [class]="hostClasses()">
31
- <table
32
- mat-table
33
- [dataSource]="data()"
34
- matSort
35
- (matSortChange)="mfSortChange.emit($event)"
36
- >
37
- @for (col of columns(); track col.key) {
38
- <ng-container [matColumnDef]="col.key">
39
- @if (col.sortable) {
40
- <th mat-header-cell *matHeaderCellDef mat-sort-header>{{ col.header }}</th>
41
- } @else {
42
- <th mat-header-cell *matHeaderCellDef>{{ col.header }}</th>
43
- }
44
- <td mat-cell *matCellDef="let row">{{ row[col.key] }}</td>
45
- </ng-container>
46
- }
47
-
48
- @if (rowActionLabel()) {
49
- <ng-container [matColumnDef]="actionColumnKey">
50
- <th mat-header-cell *matHeaderCellDef class="mf-table__actions-header">
51
- {{ rowActionHeader() }}
52
- </th>
53
- <td mat-cell *matCellDef="let row" class="mf-table__actions-cell">
54
- <button
55
- mat-button
56
- type="button"
57
- class="mf-table__action"
58
- [attr.aria-label]="getRowActionAriaLabel(row)"
59
- (click)="emitRowAction(row)"
60
- >
61
- {{ rowActionLabel() }}
62
- </button>
63
- </td>
64
- </ng-container>
65
- }
66
-
67
- <tr mat-header-row *matHeaderRowDef="displayedColumns()"></tr>
68
- <tr mat-row *matRowDef="let row; columns: displayedColumns()"></tr>
69
- </table>
70
- </div>
71
- `,
72
- styleUrl: './mf-table.component.css',
73
- changeDetection: ChangeDetectionStrategy.OnPush,
74
- })
75
- export class MfTableComponent {
76
- protected readonly actionColumnKey = 'mf-row-action';
77
-
78
- /** Columnas de la tabla */
79
- readonly columns = input.required<MfTableColumn[]>();
80
- /** Datos de la tabla */
81
- readonly data = input.required<Record<string, unknown>[]>();
82
- /** Variante visual */
83
- readonly variant = input<MfTableVariant>('default');
84
- /** Texto visible del botón de acción por fila */
85
- readonly rowActionLabel = input<string | undefined>(undefined);
86
- /** Cabecera visible de la columna de acción */
87
- readonly rowActionHeader = input('Actions');
88
- readonly rowActionAriaLabel = input<
89
- ((row: Record<string, unknown>) => string) | undefined
90
- >(undefined);
91
-
92
- readonly mfSortChange = output<Sort>();
93
- readonly mfRowAction = output<Record<string, unknown>>();
94
- /** @deprecated usa `mfRowAction` para interacciones explícitas por fila */
95
- readonly mfRowClick = output<Record<string, unknown>>();
96
-
97
- readonly displayedColumns = computed(() => {
98
- const columns = this.columns().map((column) => column.key);
99
- if (this.rowActionLabel()) {
100
- columns.push(this.actionColumnKey);
101
- }
102
- return columns;
103
- });
104
-
105
- readonly hostClasses = computed(() => {
106
- return ['mf-table', `mf-table--${this.variant()}`].join(' ');
107
- });
108
-
109
- emitRowAction(row: Record<string, unknown>): void {
110
- this.mfRowAction.emit(row);
111
- this.mfRowClick.emit(row);
112
- }
113
-
114
- getRowActionAriaLabel(row: Record<string, unknown>): string | null {
115
- return this.rowActionAriaLabel()?.(row) ?? this.rowActionLabel() ?? null;
116
- }
117
- }
@@ -1,2 +0,0 @@
1
- export { MfTabsComponent } from './mf-tabs.component';
2
- export type { MfTab, MfTabsVariant } from './mf-tabs.component';
@@ -1,31 +0,0 @@
1
- :host {
2
- display: block;
3
- }
4
-
5
- .mf-tabs .mat-mdc-tab-header {
6
- border-bottom: 1px solid var(--mf-color-border) !important;
7
- }
8
-
9
- .mf-tabs .mat-mdc-tab:not(.mdc-tab--active) .mdc-tab__text-label {
10
- color: var(--mf-color-neutral-400) !important;
11
- font-family: var(--mf-font-base) !important;
12
- font-weight: var(--mf-weight-medium) !important;
13
- }
14
-
15
- .mf-tabs .mat-mdc-tab.mdc-tab--active .mdc-tab__text-label {
16
- color: var(--mf-color-brand) !important;
17
- font-family: var(--mf-font-base) !important;
18
- font-weight: var(--mf-weight-bold) !important;
19
- }
20
-
21
- .mf-tabs .mat-mdc-tab-header .mdc-tab-indicator__content--underline {
22
- border-color: var(--mf-color-brand) !important;
23
- }
24
-
25
- .mf-tabs__icon {
26
- margin-right: var(--mf-space-2);
27
- font-size: 1.1em;
28
- height: 1.1em;
29
- width: 1.1em;
30
- vertical-align: middle;
31
- }
@@ -1,50 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
- import { MfTabsComponent } from './mf-tabs.component';
3
- import { NoopAnimationsModule } from '@angular/platform-browser/animations';
4
-
5
- describe('MfTabsComponent', () => {
6
- let fixture: ComponentFixture<MfTabsComponent>;
7
- let component: MfTabsComponent;
8
-
9
- const testTabs = [
10
- { label: 'Tab 1' },
11
- { label: 'Tab 2' },
12
- { label: 'Tab 3', disabled: true },
13
- ];
14
-
15
- beforeEach(async () => {
16
- await TestBed.configureTestingModule({
17
- imports: [MfTabsComponent, NoopAnimationsModule],
18
- }).compileComponents();
19
-
20
- fixture = TestBed.createComponent(MfTabsComponent);
21
- component = fixture.componentInstance;
22
- fixture.componentRef.setInput('tabs', testTabs);
23
- fixture.detectChanges();
24
- });
25
-
26
- it('should create', () => {
27
- expect(component).toBeTruthy();
28
- });
29
-
30
- it('should render tabs', () => {
31
- const tabLabels = fixture.nativeElement.querySelectorAll('.mat-mdc-tab');
32
- expect(tabLabels.length).toBe(3);
33
- });
34
-
35
- it('should apply default variant', () => {
36
- expect(component.hostClasses()).toContain('mf-tabs--default');
37
- });
38
-
39
- it('should apply stretched variant', () => {
40
- fixture.componentRef.setInput('variant', 'stretched');
41
- expect(component.hostClasses()).toContain('mf-tabs--stretched');
42
- });
43
-
44
- it('should emit index change', () => {
45
- const spy = vi.fn();
46
- component.mfSelectedIndexChange.subscribe(spy);
47
- component.mfSelectedIndexChange.emit(1);
48
- expect(spy).toHaveBeenCalledWith(1);
49
- });
50
- });
@@ -1,62 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- output,
7
- } from '@angular/core';
8
- import { MatTabsModule } from '@angular/material/tabs';
9
- import { MatIconModule } from '@angular/material/icon';
10
-
11
- export interface MfTab {
12
- label: string;
13
- icon?: string;
14
- disabled?: boolean;
15
- }
16
-
17
- export type MfTabsVariant = 'default' | 'stretched';
18
-
19
- /**
20
- * Tabs de la librería ng-comps.
21
- * Envuelve Angular Material `mat-tab-group` y expone una API uniforme
22
- * con look and feel de marca.
23
- */
24
- @Component({
25
- selector: 'mf-tabs',
26
- imports: [MatTabsModule, MatIconModule],
27
- template: `
28
- <mat-tab-group
29
- [selectedIndex]="selectedIndex()"
30
- [class]="hostClasses()"
31
- [mat-stretch-tabs]="variant() === 'stretched'"
32
- (selectedIndexChange)="mfSelectedIndexChange.emit($event)"
33
- >
34
- @for (tab of tabs(); track tab.label) {
35
- <mat-tab [disabled]="tab.disabled ?? false">
36
- <ng-template mat-tab-label>
37
- @if (tab.icon) {
38
- <mat-icon class="mf-tabs__icon" aria-hidden="true">{{ tab.icon }}</mat-icon>
39
- }
40
- {{ tab.label }}
41
- </ng-template>
42
- </mat-tab>
43
- }
44
- </mat-tab-group>
45
- `,
46
- styleUrl: './mf-tabs.component.css',
47
- changeDetection: ChangeDetectionStrategy.OnPush,
48
- })
49
- export class MfTabsComponent {
50
- /** Pestañas */
51
- readonly tabs = input.required<MfTab[]>();
52
- /** Índice seleccionado */
53
- readonly selectedIndex = input(0);
54
- /** Variante visual */
55
- readonly variant = input<MfTabsVariant>('default');
56
-
57
- readonly mfSelectedIndexChange = output<number>();
58
-
59
- readonly hostClasses = computed(() => {
60
- return ['mf-tabs', `mf-tabs--${this.variant()}`].join(' ');
61
- });
62
- }
@@ -1,2 +0,0 @@
1
- export { MfTextareaComponent } from './mf-textarea.component';
2
- export type { MfTextareaSize, MfTextareaResize } from './mf-textarea.component';
@@ -1,48 +0,0 @@
1
- :host {
2
- display: block;
3
- }
4
-
5
- .mf-textarea.mat-mdc-form-field {
6
- font-family: var(--mf-font-base) !important;
7
- width: 100%;
8
- }
9
-
10
- .mf-textarea textarea.mat-mdc-input-element {
11
- font-family: var(--mf-font-base) !important;
12
- line-height: var(--mf-leading-normal) !important;
13
- }
14
-
15
- .mf-textarea .mdc-notched-outline__leading,
16
- .mf-textarea .mdc-notched-outline__notch,
17
- .mf-textarea .mdc-notched-outline__trailing {
18
- border-color: var(--mf-color-border) !important;
19
- }
20
-
21
- .mf-textarea.mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,
22
- .mf-textarea.mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,
23
- .mf-textarea.mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing {
24
- border-color: var(--mf-color-brand) !important;
25
- }
26
-
27
- .mf-textarea .mdc-notched-outline {
28
- border-radius: var(--mf-radius-md) !important;
29
- }
30
-
31
- /* ── Tamaños ───────────────────────────────────────────────────── */
32
- .mf-textarea--sm textarea.mat-mdc-input-element {
33
- font-size: var(--mf-text-sm) !important;
34
- }
35
-
36
- .mf-textarea--md textarea.mat-mdc-input-element {
37
- font-size: var(--mf-text-base) !important;
38
- }
39
-
40
- .mf-textarea--lg textarea.mat-mdc-input-element {
41
- font-size: var(--mf-text-lg) !important;
42
- }
43
-
44
- /* ── Resize ────────────────────────────────────────────────────── */
45
- .mf-textarea--resize-none textarea { resize: none; }
46
- .mf-textarea--resize-vertical textarea { resize: vertical; }
47
- .mf-textarea--resize-horizontal textarea { resize: horizontal; }
48
- .mf-textarea--resize-both textarea { resize: both; }
@@ -1,55 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
- import { MfTextareaComponent } from './mf-textarea.component';
3
- import { NoopAnimationsModule } from '@angular/platform-browser/animations';
4
-
5
- describe('MfTextareaComponent', () => {
6
- let fixture: ComponentFixture<MfTextareaComponent>;
7
- let component: MfTextareaComponent;
8
-
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [MfTextareaComponent, NoopAnimationsModule],
12
- }).compileComponents();
13
-
14
- fixture = TestBed.createComponent(MfTextareaComponent);
15
- component = fixture.componentInstance;
16
- fixture.detectChanges();
17
- });
18
-
19
- it('should create', () => {
20
- expect(component).toBeTruthy();
21
- });
22
-
23
- it('should render textarea', () => {
24
- const textarea = fixture.nativeElement.querySelector('textarea');
25
- expect(textarea).toBeTruthy();
26
- });
27
-
28
- it('should apply md size by default', () => {
29
- expect(component.hostClasses()).toContain('mf-textarea--md');
30
- });
31
-
32
- it('should have default 4 rows', () => {
33
- expect(component.rows()).toBe(4);
34
- });
35
-
36
- it('should apply vertical resize by default', () => {
37
- expect(component.hostClasses()).toContain('mf-textarea--resize-vertical');
38
- });
39
-
40
- it('should render label when provided', () => {
41
- fixture.componentRef.setInput('label', 'Description');
42
- fixture.detectChanges();
43
- const label = fixture.nativeElement.querySelector('mat-label');
44
- expect(label?.textContent).toContain('Description');
45
- });
46
-
47
- it('should emit input event', () => {
48
- const spy = vi.fn();
49
- component.mfInput.subscribe(spy);
50
- const textarea = fixture.nativeElement.querySelector('textarea');
51
- textarea.value = 'Hello';
52
- textarea.dispatchEvent(new Event('input'));
53
- expect(spy).toHaveBeenCalledWith('Hello');
54
- });
55
- });