angular-dev-utils 1.0.1 → 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.
Files changed (40) hide show
  1. package/esm2022/angular-dev-utils.mjs +5 -0
  2. package/esm2022/lib/components/button/button.component.mjs +68 -0
  3. package/esm2022/lib/components/card/card.component.mjs +78 -0
  4. package/esm2022/lib/components/input/input.component.mjs +141 -0
  5. package/esm2022/lib/components/modal/modal.component.mjs +102 -0
  6. package/esm2022/lib/components/spinner/spinner.component.mjs +44 -0
  7. package/esm2022/lib/components/table/table.component.mjs +240 -0
  8. package/esm2022/lib/models/types.mjs +2 -0
  9. package/esm2022/lib/services/modal.service.mjs +102 -0
  10. package/esm2022/public-api.mjs +15 -0
  11. package/fesm2022/angular-dev-utils.mjs +765 -0
  12. package/fesm2022/angular-dev-utils.mjs.map +1 -0
  13. package/index.d.ts +5 -0
  14. package/lib/components/button/button.component.d.ts +16 -0
  15. package/lib/components/card/card.component.d.ts +12 -0
  16. package/lib/components/input/input.component.d.ts +27 -0
  17. package/lib/components/modal/modal.component.d.ts +17 -0
  18. package/lib/components/spinner/spinner.component.d.ts +11 -0
  19. package/lib/components/table/table.component.d.ts +29 -0
  20. package/{src/lib/models/types.ts → lib/models/types.d.ts} +15 -20
  21. package/lib/services/modal.service.d.ts +21 -0
  22. package/package.json +15 -26
  23. package/{src/public-api.ts → public-api.d.ts} +0 -9
  24. package/.github/workflows/ci.yml +0 -39
  25. package/.github/workflows/publish.yml +0 -53
  26. package/angular.json +0 -43
  27. package/ng-package.json +0 -8
  28. package/src/lib/components/button/button.component.ts +0 -100
  29. package/src/lib/components/card/card.component.ts +0 -101
  30. package/src/lib/components/input/input.component.ts +0 -141
  31. package/src/lib/components/modal/modal.component.ts +0 -139
  32. package/src/lib/components/spinner/spinner.component.ts +0 -64
  33. package/src/lib/components/table/table.component.ts +0 -240
  34. package/src/lib/services/modal.service.ts +0 -120
  35. package/src/lib/styles.scss +0 -8
  36. package/tailwind.config.js +0 -25
  37. package/tsconfig.json +0 -32
  38. package/tsconfig.lib.json +0 -13
  39. package/tsconfig.lib.prod.json +0 -9
  40. package/tsconfig.spec.json +0 -13
@@ -1,101 +0,0 @@
1
- import { Component, Input } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
-
4
- @Component({
5
- selector: 'adu-card',
6
- standalone: true,
7
- imports: [CommonModule],
8
- template: `
9
- <div [class]="cardClasses">
10
- <div *ngIf="hasHeader" class="adu-card-header">
11
- <ng-content select="[card-header]"></ng-content>
12
- </div>
13
-
14
- <div class="adu-card-body">
15
- <ng-content></ng-content>
16
- </div>
17
-
18
- <div *ngIf="hasFooter" class="adu-card-footer">
19
- <ng-content select="[card-footer]"></ng-content>
20
- </div>
21
- </div>
22
- `,
23
- styles: [`
24
- .adu-card {
25
- @apply rounded-lg border border-zinc-200 bg-white text-zinc-950 shadow-sm;
26
- }
27
-
28
- .adu-card-hoverable:hover {
29
- @apply shadow-md;
30
- }
31
-
32
- .adu-card-shadow-sm {
33
- @apply shadow-sm;
34
- }
35
-
36
- .adu-card-shadow-md {
37
- @apply shadow-md;
38
- }
39
-
40
- .adu-card-shadow-lg {
41
- @apply shadow-lg;
42
- }
43
-
44
- .adu-card-shadow-xl {
45
- @apply shadow-xl;
46
- }
47
-
48
- .adu-card-header {
49
- @apply flex flex-col space-y-1.5 p-6;
50
- }
51
-
52
- .adu-card-body {
53
- @apply p-6 pt-0;
54
- }
55
-
56
- .adu-card-body-compact {
57
- @apply p-4 pt-0;
58
- }
59
-
60
- .adu-card-body-spacious {
61
- @apply p-8 pt-0;
62
- }
63
-
64
- .adu-card-footer {
65
- @apply flex items-center p-6 pt-0;
66
- }
67
- `]
68
- })
69
- export class CardComponent {
70
- @Input() shadow: 'none' | 'sm' | 'md' | 'lg' | 'xl' = 'sm';
71
- @Input() hoverable = false;
72
- @Input() padding: 'compact' | 'normal' | 'spacious' = 'normal';
73
- @Input() hasHeader = false;
74
- @Input() hasFooter = false;
75
-
76
- get cardClasses(): string {
77
- const classes = ['adu-card'];
78
-
79
- if (this.shadow !== 'none') {
80
- classes.push(`adu-card-shadow-${this.shadow}`);
81
- }
82
-
83
- if (this.hoverable) {
84
- classes.push('adu-card-hoverable');
85
- }
86
-
87
- return classes.join(' ');
88
- }
89
-
90
- get bodyClasses(): string {
91
- const classes = ['adu-card-body'];
92
-
93
- if (this.padding === 'compact') {
94
- classes.push('adu-card-body-compact');
95
- } else if (this.padding === 'spacious') {
96
- classes.push('adu-card-body-spacious');
97
- }
98
-
99
- return classes.join(' ');
100
- }
101
- }
@@ -1,141 +0,0 @@
1
- import { Component, Input, forwardRef } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
4
- import { InputType, InputSize } from '../../models/types';
5
-
6
- @Component({
7
- selector: 'adu-input',
8
- standalone: true,
9
- imports: [CommonModule],
10
- providers: [
11
- {
12
- provide: NG_VALUE_ACCESSOR,
13
- useExisting: forwardRef(() => InputComponent),
14
- multi: true
15
- }
16
- ],
17
- template: `
18
- <div class="adu-input-wrapper">
19
- <label *ngIf="label" [for]="id" class="adu-input-label">
20
- {{ label }}
21
- <span *ngIf="required" class="text-red-500">*</span>
22
- </label>
23
-
24
- <div class="relative">
25
- <input
26
- [id]="id"
27
- [type]="type"
28
- [placeholder]="placeholder"
29
- [disabled]="disabled"
30
- [readonly]="readonly"
31
- [value]="value"
32
- [class]="inputClasses"
33
- (input)="onInputChange($event)"
34
- (blur)="onTouched()"
35
- />
36
- <span *ngIf="icon" class="adu-input-icon">{{ icon }}</span>
37
- </div>
38
-
39
- <p *ngIf="error" class="adu-input-error">{{ error }}</p>
40
- <p *ngIf="hint && !error" class="adu-input-hint">{{ hint }}</p>
41
- </div>
42
- `,
43
- styles: [`
44
- .adu-input-wrapper {
45
- @apply w-full;
46
- }
47
-
48
- .adu-input-label {
49
- @apply block text-sm font-medium text-zinc-900 mb-1.5;
50
- }
51
-
52
- .adu-input {
53
- @apply flex w-full rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm;
54
- @apply ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium;
55
- @apply placeholder:text-zinc-500;
56
- @apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 focus-visible:ring-offset-2;
57
- @apply disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-zinc-50;
58
- }
59
-
60
- .adu-input-sm {
61
- @apply h-9 px-3 text-sm;
62
- }
63
-
64
- .adu-input-md {
65
- @apply h-10 px-3 text-sm;
66
- }
67
-
68
- .adu-input-lg {
69
- @apply h-11 px-4 text-base;
70
- }
71
-
72
- .adu-input-error-state {
73
- @apply border-red-500 focus-visible:ring-red-500;
74
- }
75
-
76
- .adu-input-icon {
77
- @apply absolute right-3 top-1/2 -translate-y-1/2 text-zinc-400 pointer-events-none;
78
- }
79
-
80
- .adu-input-error {
81
- @apply mt-1.5 text-sm text-red-600 font-medium;
82
- }
83
-
84
- .adu-input-hint {
85
- @apply mt-1.5 text-sm text-zinc-500;
86
- }
87
- `]
88
- })
89
- export class InputComponent implements ControlValueAccessor {
90
- @Input() id = `adu-input-${Math.random().toString(36).substr(2, 9)}`;
91
- @Input() label = '';
92
- @Input() type: InputType = 'text';
93
- @Input() placeholder = '';
94
- @Input() size: InputSize = 'md';
95
- @Input() disabled = false;
96
- @Input() readonly = false;
97
- @Input() required = false;
98
- @Input() error = '';
99
- @Input() hint = '';
100
- @Input() icon = '';
101
-
102
- value = '';
103
- onChange: (value: string) => void = () => { };
104
- onTouched: () => void = () => { };
105
-
106
- get inputClasses(): string {
107
- const classes = ['adu-input', `adu-input-${this.size}`];
108
-
109
- if (this.error) {
110
- classes.push('adu-input-error-state');
111
- }
112
-
113
- if (this.icon) {
114
- classes.push('pr-10');
115
- }
116
-
117
- return classes.join(' ');
118
- }
119
-
120
- onInputChange(event: Event): void {
121
- const input = event.target as HTMLInputElement;
122
- this.value = input.value;
123
- this.onChange(this.value);
124
- }
125
-
126
- writeValue(value: string): void {
127
- this.value = value || '';
128
- }
129
-
130
- registerOnChange(fn: (value: string) => void): void {
131
- this.onChange = fn;
132
- }
133
-
134
- registerOnTouched(fn: () => void): void {
135
- this.onTouched = fn;
136
- }
137
-
138
- setDisabledState(isDisabled: boolean): void {
139
- this.disabled = isDisabled;
140
- }
141
- }
@@ -1,139 +0,0 @@
1
- import { Component, Input, Output, EventEmitter } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
-
4
- @Component({
5
- selector: 'adu-modal',
6
- standalone: true,
7
- imports: [CommonModule],
8
- template: `
9
- <div class="adu-modal-wrapper" *ngIf="isOpen" (click)="onBackdropClick()">
10
- <div [class]="modalClasses" (click)="$event.stopPropagation()">
11
- <button
12
- *ngIf="showCloseButton"
13
- class="adu-modal-close"
14
- (click)="close()"
15
- aria-label="Close modal"
16
- >
17
- ×
18
- </button>
19
-
20
- <div *ngIf="title" class="adu-modal-title">
21
- {{ title }}
22
- </div>
23
-
24
- <div class="adu-modal-body">
25
- <ng-content></ng-content>
26
- </div>
27
-
28
- <div *ngIf="hasFooter" class="adu-modal-footer">
29
- <ng-content select="[modal-footer]"></ng-content>
30
- </div>
31
- </div>
32
- </div>
33
- `,
34
- styles: [`
35
- .adu-modal-wrapper {
36
- @apply fixed inset-0 z-50 flex items-center justify-center p-4;
37
- background: rgba(0, 0, 0, 0.5);
38
- backdrop-filter: blur(4px);
39
- animation: fadeIn 0.15s ease-out;
40
- }
41
-
42
- .adu-modal-content {
43
- @apply relative bg-white rounded-lg shadow-lg max-h-[90vh] overflow-hidden;
44
- animation: slideUp 0.2s ease-out;
45
- }
46
-
47
- .adu-modal-sm {
48
- @apply w-full max-w-sm;
49
- }
50
-
51
- .adu-modal-md {
52
- @apply w-full max-w-lg;
53
- }
54
-
55
- .adu-modal-lg {
56
- @apply w-full max-w-2xl;
57
- }
58
-
59
- .adu-modal-xl {
60
- @apply w-full max-w-4xl;
61
- }
62
-
63
- .adu-modal-full {
64
- @apply w-full h-full max-w-none rounded-none;
65
- }
66
-
67
- .adu-modal-close {
68
- @apply absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white;
69
- @apply transition-opacity hover:opacity-100;
70
- @apply focus:outline-none focus:ring-2 focus:ring-zinc-950 focus:ring-offset-2;
71
- @apply disabled:pointer-events-none;
72
- @apply text-zinc-500 hover:text-zinc-900 text-2xl font-light w-6 h-6 flex items-center justify-center;
73
- }
74
-
75
- .adu-modal-title {
76
- @apply flex flex-col space-y-1.5 text-center sm:text-left p-6 pb-4;
77
- @apply text-lg font-semibold leading-none tracking-tight text-zinc-950;
78
- }
79
-
80
- .adu-modal-body {
81
- @apply p-6 pt-0 overflow-y-auto;
82
- }
83
-
84
- .adu-modal-footer {
85
- @apply flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 p-6 pt-4;
86
- }
87
-
88
- @keyframes fadeIn {
89
- from { opacity: 0; }
90
- to { opacity: 1; }
91
- }
92
-
93
- @keyframes slideUp {
94
- from {
95
- opacity: 0;
96
- transform: translateY(4px) scale(0.98);
97
- }
98
- to {
99
- opacity: 1;
100
- transform: translateY(0) scale(1);
101
- }
102
- }
103
-
104
- .animate-fadeIn {
105
- animation: fadeIn 0.15s ease-out;
106
- }
107
-
108
- .animate-slideUp {
109
- animation: slideUp 0.3s ease-out;
110
- }
111
- `]
112
- })
113
- export class ModalComponent {
114
- @Input() isOpen = false;
115
- @Input() title = '';
116
- @Input() size: 'sm' | 'md' | 'lg' | 'xl' | 'full' = 'md';
117
- @Input() closeOnBackdrop = true;
118
- @Input() showCloseButton = true;
119
- @Input() hasFooter = false;
120
-
121
- @Output() isOpenChange = new EventEmitter<boolean>();
122
- @Output() closed = new EventEmitter<void>();
123
-
124
- get modalClasses(): string {
125
- return ['adu-modal-content', `adu-modal-${this.size}`].join(' ');
126
- }
127
-
128
- close(): void {
129
- this.isOpen = false;
130
- this.isOpenChange.emit(false);
131
- this.closed.emit();
132
- }
133
-
134
- onBackdropClick(): void {
135
- if (this.closeOnBackdrop) {
136
- this.close();
137
- }
138
- }
139
- }
@@ -1,64 +0,0 @@
1
- import { Component, Input } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { SpinnerSize, SpinnerColor } from '../../models/types';
4
-
5
- @Component({
6
- selector: 'adu-spinner',
7
- standalone: true,
8
- imports: [CommonModule],
9
- template: `
10
- <div *ngIf="overlay" class="adu-spinner-overlay">
11
- <div [class]="spinnerClasses"></div>
12
- <p *ngIf="message" class="adu-spinner-message">{{ message }}</p>
13
- </div>
14
-
15
- <div *ngIf="!overlay" [class]="spinnerClasses"></div>
16
- `,
17
- styles: [`
18
- .adu-spinner {
19
- @apply inline-block border-2 border-zinc-200 border-t-zinc-900 rounded-full animate-spin;
20
- }
21
-
22
- .adu-spinner-sm {
23
- @apply w-4 h-4 border-2;
24
- }
25
-
26
- .adu-spinner-md {
27
- @apply w-6 h-6 border-2;
28
- }
29
-
30
- .adu-spinner-lg {
31
- @apply w-10 h-10 border-[3px];
32
- }
33
-
34
- .adu-spinner-primary {
35
- @apply border-zinc-200 border-t-zinc-900;
36
- }
37
-
38
- .adu-spinner-secondary {
39
- @apply border-zinc-300 border-t-zinc-600;
40
- }
41
-
42
- .adu-spinner-white {
43
- @apply border-zinc-100 border-t-white;
44
- }
45
-
46
- .adu-spinner-overlay {
47
- @apply fixed inset-0 bg-black/50 backdrop-blur-sm flex flex-col items-center justify-center z-50;
48
- }
49
-
50
- .adu-spinner-message {
51
- @apply mt-4 text-white text-sm font-medium;
52
- }
53
- `]
54
- })
55
- export class SpinnerComponent {
56
- @Input() size: SpinnerSize = 'md';
57
- @Input() color: SpinnerColor = 'primary';
58
- @Input() overlay = false;
59
- @Input() message = '';
60
-
61
- get spinnerClasses(): string {
62
- return ['adu-spinner', `adu-spinner-${this.size}`, `adu-spinner-${this.color}`].join(' ');
63
- }
64
- }
@@ -1,240 +0,0 @@
1
- import { Component, Input, Output, EventEmitter, ContentChild, TemplateRef } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { TableColumn, TableConfig } from '../../models/types';
4
-
5
- @Component({
6
- selector: 'adu-table',
7
- standalone: true,
8
- imports: [CommonModule],
9
- template: `
10
- <div class="adu-table-container">
11
- <table class="adu-table" [class.adu-table-striped]="config.striped" [class.adu-table-hoverable]="config.hoverable">
12
- <thead class="adu-table-header">
13
- <tr>
14
- <th
15
- *ngFor="let column of columns"
16
- [style.width]="column.width"
17
- [class.adu-table-sortable]="column.sortable && config.sortable"
18
- (click)="onSort(column)"
19
- class="adu-table-th"
20
- >
21
- <div class="flex items-center justify-between">
22
- <span>{{ column.label }}</span>
23
- <span *ngIf="column.sortable && config.sortable" class="adu-table-sort-icon">
24
- <span *ngIf="sortColumn === column.key">
25
- {{ sortDirection === 'asc' ? '↑' : '↓' }}
26
- </span>
27
- <span *ngIf="sortColumn !== column.key" class="text-gray-300">↕</span>
28
- </span>
29
- </div>
30
- </th>
31
- </tr>
32
- </thead>
33
- <tbody class="adu-table-body">
34
- <tr *ngFor="let row of paginatedData; let i = index" class="adu-table-row">
35
- <td *ngFor="let column of columns" class="adu-table-td">
36
- <ng-container *ngIf="cellTemplate; else defaultCell">
37
- <ng-container *ngTemplateOutlet="cellTemplate; context: { $implicit: row, column: column }"></ng-container>
38
- </ng-container>
39
- <ng-template #defaultCell>
40
- {{ getCellValue(row, column) }}
41
- </ng-template>
42
- </td>
43
- </tr>
44
- <tr *ngIf="paginatedData.length === 0" class="adu-table-empty">
45
- <td [attr.colspan]="columns.length" class="text-center py-8 text-gray-500">
46
- <ng-content select="[empty-state]"></ng-content>
47
- <span *ngIf="!hasEmptyState">No data available</span>
48
- </td>
49
- </tr>
50
- </tbody>
51
- </table>
52
-
53
- <!-- Pagination -->
54
- <div *ngIf="config.pageable && totalPages > 1" class="adu-table-pagination">
55
- <button
56
- class="adu-pagination-btn"
57
- [disabled]="currentPage === 1"
58
- (click)="goToPage(currentPage - 1)"
59
- >
60
- Previous
61
- </button>
62
-
63
- <div class="adu-pagination-info">
64
- Page {{ currentPage }} of {{ totalPages }}
65
- </div>
66
-
67
- <button
68
- class="adu-pagination-btn"
69
- [disabled]="currentPage === totalPages"
70
- (click)="goToPage(currentPage + 1)"
71
- >
72
- Next
73
- </button>
74
- </div>
75
- </div>
76
- `,
77
- styles: [`
78
- .adu-table-container {
79
- @apply w-full overflow-x-auto rounded-md border border-zinc-200;
80
- }
81
-
82
- .adu-table {
83
- @apply w-full caption-bottom text-sm;
84
- }
85
-
86
- .adu-table-header {
87
- @apply border-b border-zinc-200;
88
- }
89
-
90
- .adu-table-th {
91
- @apply h-12 px-4 text-left align-middle font-medium text-zinc-500;
92
- @apply [&:has([role=checkbox])]:pr-0;
93
- }
94
-
95
- .adu-table-sortable {
96
- @apply cursor-pointer hover:text-zinc-900 transition-colors;
97
- }
98
-
99
- .adu-table-sort-icon {
100
- @apply ml-2 inline-block text-zinc-400;
101
- }
102
-
103
- .adu-table-body {
104
- @apply [&_tr:last-child]:border-0;
105
- }
106
-
107
- .adu-table-row {
108
- @apply border-b border-zinc-200 transition-colors;
109
- @apply hover:bg-zinc-50/50;
110
- @apply data-[state=selected]:bg-zinc-100;
111
- }
112
-
113
- .adu-table-striped .adu-table-row:nth-child(even) {
114
- @apply bg-zinc-50/30;
115
- }
116
-
117
- .adu-table-hoverable .adu-table-row:hover {
118
- @apply bg-zinc-50;
119
- }
120
-
121
- .adu-table-td {
122
- @apply p-4 align-middle text-zinc-900;
123
- @apply [&:has([role=checkbox])]:pr-0;
124
- }
125
-
126
- .adu-table-empty {
127
- @apply text-center py-10 text-zinc-500;
128
- }
129
-
130
- .adu-table-pagination {
131
- @apply flex items-center justify-between px-4 py-3 border-t border-zinc-200 bg-zinc-50/50;
132
- }
133
-
134
- .adu-pagination-btn {
135
- @apply inline-flex items-center justify-center rounded-md text-sm font-medium;
136
- @apply ring-offset-white transition-colors;
137
- @apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 focus-visible:ring-offset-2;
138
- @apply disabled:pointer-events-none disabled:opacity-50;
139
- @apply border border-zinc-200 bg-white hover:bg-zinc-100 hover:text-zinc-900;
140
- @apply h-9 px-4 py-2;
141
- }
142
-
143
- .adu-pagination-info {
144
- @apply text-sm text-zinc-600 font-medium;
145
- }
146
- `]
147
- })
148
- export class TableComponent<T = any> {
149
- @Input() data: T[] = [];
150
- @Input() columns: TableColumn<T>[] = [];
151
- @Input() config: TableConfig = {
152
- sortable: true,
153
- pageable: true,
154
- pageSize: 10,
155
- striped: true,
156
- hoverable: true
157
- };
158
-
159
- @ContentChild('cellTemplate') cellTemplate?: TemplateRef<any>;
160
- @Output() rowClicked = new EventEmitter<T>();
161
- @Output() sortChanged = new EventEmitter<{ column: string; direction: 'asc' | 'desc' }>();
162
-
163
- sortColumn = '';
164
- sortDirection: 'asc' | 'desc' = 'asc';
165
- currentPage = 1;
166
- hasEmptyState = false;
167
-
168
- ngOnInit() {
169
- this.config = { ...this.getDefaultConfig(), ...this.config };
170
- }
171
-
172
- get sortedData(): T[] {
173
- if (!this.config.sortable || !this.sortColumn) {
174
- return this.data;
175
- }
176
-
177
- return [...this.data].sort((a, b) => {
178
- const aVal = this.getNestedValue(a, this.sortColumn);
179
- const bVal = this.getNestedValue(b, this.sortColumn);
180
-
181
- if (aVal < bVal) return this.sortDirection === 'asc' ? -1 : 1;
182
- if (aVal > bVal) return this.sortDirection === 'asc' ? 1 : -1;
183
- return 0;
184
- });
185
- }
186
-
187
- get paginatedData(): T[] {
188
- if (!this.config.pageable) {
189
- return this.sortedData;
190
- }
191
-
192
- const start = (this.currentPage - 1) * (this.config.pageSize || 10);
193
- const end = start + (this.config.pageSize || 10);
194
- return this.sortedData.slice(start, end);
195
- }
196
-
197
- get totalPages(): number {
198
- return Math.ceil(this.data.length / (this.config.pageSize || 10));
199
- }
200
-
201
- onSort(column: TableColumn<T>): void {
202
- if (!column.sortable || !this.config.sortable) return;
203
-
204
- if (this.sortColumn === column.key) {
205
- this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
206
- } else {
207
- this.sortColumn = column.key;
208
- this.sortDirection = 'asc';
209
- }
210
-
211
- this.sortChanged.emit({ column: column.key, direction: this.sortDirection });
212
- }
213
-
214
- goToPage(page: number): void {
215
- if (page >= 1 && page <= this.totalPages) {
216
- this.currentPage = page;
217
- }
218
- }
219
-
220
- getCellValue(row: T, column: TableColumn<T>): any {
221
- if (column.cellTemplate) {
222
- return column.cellTemplate(row);
223
- }
224
- return this.getNestedValue(row, column.key);
225
- }
226
-
227
- private getNestedValue(obj: any, path: string): any {
228
- return path.split('.').reduce((current, prop) => current?.[prop], obj);
229
- }
230
-
231
- private getDefaultConfig(): TableConfig {
232
- return {
233
- sortable: true,
234
- pageable: true,
235
- pageSize: 10,
236
- striped: true,
237
- hoverable: true
238
- };
239
- }
240
- }