@avoraui/av-data-table 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,568 @@
1
+ /* ──────────────────────────────────────────
2
+ AvoraUI Data Table — Premium Stylesheet
3
+ ────────────────────────────────────────── */
4
+
5
+ /* ─── CSS Variables (Design Tokens) ─── */
6
+ :host {
7
+ --av-primary: #4361ee;
8
+ --av-primary-light: #eef1ff;
9
+ --av-primary-hover: #3651d4;
10
+ --av-accent: #f72585;
11
+ --av-accent-light: #fee2ef;
12
+ --av-edit: #4cc9f0;
13
+ --av-edit-hover: #3ab8df;
14
+ --av-delete: #ef476f;
15
+ --av-delete-hover: #d63d62;
16
+ --av-text-primary: #1e293b;
17
+ --av-text-secondary: #64748b;
18
+ --av-text-muted: #94a3b8;
19
+ --av-bg-surface: #ffffff;
20
+ --av-bg-muted: #f8fafc;
21
+ --av-border: #e2e8f0;
22
+ --av-border-hover: #cbd5e1;
23
+ --av-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
24
+ --av-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
25
+ --av-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.1);
26
+ --av-radius-sm: 6px;
27
+ --av-radius-md: 10px;
28
+ --av-radius-lg: 14px;
29
+ --av-transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
30
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
31
+ }
32
+
33
+ /* ─── Material Card Reset ─── */
34
+ mat-card {
35
+ width: 100%;
36
+ background: none;
37
+ border: unset;
38
+ box-shadow: unset;
39
+ margin: 0;
40
+ padding: 0;
41
+ }
42
+
43
+ mat-card-content {
44
+ border-radius: unset !important;
45
+ padding: 0 !important;
46
+ background: unset;
47
+ overflow: hidden;
48
+ }
49
+
50
+ mat-icon {
51
+ font-size: 18px;
52
+ width: 18px;
53
+ height: 18px;
54
+ }
55
+
56
+ button:disabled {
57
+ opacity: 0.4;
58
+ cursor: not-allowed !important;
59
+ filter: grayscale(0.3);
60
+ }
61
+
62
+ /* ════════════════════════════════════════
63
+ TOP ACTION BAR — Search & Clear
64
+ ════════════════════════════════════════ */
65
+
66
+ .table-top-actions {
67
+ display: flex;
68
+ align-items: center;
69
+ padding: 12px 4px;
70
+ gap: 12px;
71
+ }
72
+
73
+ .spacer {
74
+ flex: 1;
75
+ }
76
+
77
+ .clear-filters-btn {
78
+ border-radius: var(--av-radius-sm) !important;
79
+ color: var(--av-text-secondary) !important;
80
+ border-color: var(--av-border) !important;
81
+ font-weight: 500 !important;
82
+ font-size: 13px !important;
83
+ letter-spacing: 0.3px;
84
+ transition: all var(--av-transition) !important;
85
+ padding: 0 14px !important;
86
+ height: 38px !important;
87
+ }
88
+
89
+ .clear-filters-btn:hover {
90
+ background: var(--av-accent-light) !important;
91
+ color: var(--av-accent) !important;
92
+ border-color: var(--av-accent) !important;
93
+ box-shadow: 0 2px 8px rgba(247, 37, 133, 0.12);
94
+ }
95
+
96
+ .clear-filters-btn mat-icon {
97
+ margin-right: 5px;
98
+ font-size: 17px;
99
+ width: 17px;
100
+ height: 17px;
101
+ transition: color var(--av-transition);
102
+ }
103
+
104
+ .clear-filters-btn:hover mat-icon {
105
+ color: var(--av-accent) !important;
106
+ }
107
+
108
+ .global-search-field {
109
+ /*width: 280px;*/
110
+ }
111
+
112
+ .global-search-field mat-icon {
113
+ color: var(--av-text-muted);
114
+ transition: color var(--av-transition);
115
+ }
116
+
117
+ ::ng-deep .global-search-field .mat-mdc-form-field-subscript-wrapper {
118
+ display: none;
119
+ }
120
+
121
+ /* Force icon prefix spacing — covers all Angular Material versions */
122
+ ::ng-deep .global-search-field .mat-mdc-form-field-icon-prefix,
123
+ ::ng-deep .global-search-field .mat-mdc-form-field-prefix,
124
+ ::ng-deep .global-search-field [matprefix],
125
+ ::ng-deep .global-search-field [maticonprefix] {
126
+ /*padding: 0 8px 0 12px !important;*/
127
+ /*display: flex !important;*/
128
+ /*align-items: center !important;*/
129
+ }
130
+
131
+ ::ng-deep .global-search-field .mat-mdc-form-field-icon-prefix mat-icon,
132
+ ::ng-deep .global-search-field .mat-mdc-form-field-prefix mat-icon {
133
+ font-size: 20px;
134
+ width: 20px;
135
+ /*height: 20px;*/
136
+ color: var(--av-text-muted);
137
+ }
138
+
139
+ ::ng-deep .global-search-field .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading,
140
+ ::ng-deep .global-search-field .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__notch,
141
+ ::ng-deep .global-search-field .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing {
142
+ border-color: var(--av-border) !important;
143
+ }
144
+
145
+ ::ng-deep .global-search-field.mat-focused .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading,
146
+ ::ng-deep .global-search-field.mat-focused .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__notch,
147
+ ::ng-deep .global-search-field.mat-focused .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing {
148
+ border-color: var(--av-primary) !important;
149
+ }
150
+
151
+ /* ════════════════════════════════════════
152
+ HEADER ROW
153
+ ════════════════════════════════════════ */
154
+
155
+ .item-header-row {
156
+ display: grid;
157
+ padding: 0 20px;
158
+ background: linear-gradient(135deg, #f1f5f9 0%, #e8edf3 100%);
159
+ border-bottom: 2px solid var(--av-primary);
160
+ border-radius: var(--av-radius-md) var(--av-radius-md) 0 0;
161
+ margin-top: 8px;
162
+ font-family: inherit;
163
+ letter-spacing: 0.4px;
164
+ min-height: 48px;
165
+ align-items: center;
166
+ }
167
+
168
+ .item-header-row strong {
169
+ font-weight: 700;
170
+ color: var(--av-text-primary);
171
+ font-size: 12px;
172
+ text-transform: uppercase;
173
+ letter-spacing: 0.8px;
174
+ }
175
+
176
+ /* Text alignment classes */
177
+ .header-text-left {
178
+ text-align: left;
179
+ padding-left: 16px !important;
180
+ }
181
+
182
+ .header-text-center {
183
+ text-align: center;
184
+ }
185
+
186
+ .header-text-right {
187
+ text-align: right;
188
+ }
189
+
190
+ .text-left {
191
+ text-align: left;
192
+ padding-left: 5px !important;
193
+ font-weight: 500;
194
+ }
195
+
196
+ .text-center {
197
+ text-align: center;
198
+ font-weight: 500;
199
+ }
200
+
201
+ .text-right {
202
+ text-align: right;
203
+ }
204
+
205
+ /* ─── Header Cell & Sort/Filter Controls ─── */
206
+
207
+ .header-cell {
208
+ display: flex !important;
209
+ align-items: center;
210
+ justify-content: inherit;
211
+ gap: 2px;
212
+ }
213
+
214
+ .header-content {
215
+ display: flex;
216
+ align-items: center;
217
+ cursor: pointer;
218
+ user-select: none;
219
+ flex: 1;
220
+ padding: 4px 6px;
221
+ border-radius: var(--av-radius-sm);
222
+ transition: background var(--av-transition);
223
+ }
224
+
225
+ .header-content:hover {
226
+ background: rgba(67, 97, 238, 0.08);
227
+ }
228
+
229
+ .header-content:active {
230
+ background: rgba(67, 97, 238, 0.15);
231
+ }
232
+
233
+ .sort-icon {
234
+ font-size: 16px;
235
+ width: 16px;
236
+ height: 16px;
237
+ margin-left: 4px;
238
+ color: var(--av-text-muted);
239
+ transition: all var(--av-transition);
240
+ opacity: 0.5;
241
+ }
242
+
243
+ .header-content:hover .sort-icon {
244
+ opacity: 1;
245
+ color: var(--av-primary);
246
+ }
247
+
248
+ .sort-icon.active {
249
+ color: var(--av-primary) !important;
250
+ opacity: 1 !important;
251
+ animation: sortBounce 0.3s ease;
252
+ }
253
+
254
+ @keyframes sortBounce {
255
+ 0% {
256
+ transform: scale(1);
257
+ }
258
+
259
+ 50% {
260
+ transform: scale(1.3);
261
+ }
262
+
263
+ 100% {
264
+ transform: scale(1);
265
+ }
266
+ }
267
+
268
+ .filter-btn {
269
+ width: 30px !important;
270
+ height: 30px !important;
271
+ padding: 0 !important;
272
+ display: flex !important;
273
+ align-items: center !important;
274
+ justify-content: center !important;
275
+ border-radius: var(--av-radius-sm) !important;
276
+ transition: all var(--av-transition) !important;
277
+ }
278
+
279
+ .filter-btn:hover {
280
+ background: rgba(67, 97, 238, 0.08) !important;
281
+ }
282
+
283
+ .filter-btn mat-icon {
284
+ font-size: 16px;
285
+ width: 16px;
286
+ height: 16px;
287
+ color: var(--av-text-muted);
288
+ transition: all var(--av-transition);
289
+ }
290
+
291
+ .filter-btn:hover mat-icon {
292
+ color: var(--av-primary);
293
+ }
294
+
295
+ .active-filter {
296
+ color: var(--av-primary) !important;
297
+ position: relative;
298
+ }
299
+
300
+ /* ════════════════════════════════════════
301
+ DATA ROWS
302
+ ════════════════════════════════════════ */
303
+
304
+ .item-details {
305
+ width: 100%;
306
+ margin-bottom: 0 !important;
307
+ background-color: var(--av-bg-surface);
308
+ border-left: 3px solid transparent;
309
+ border-bottom: 1px solid var(--av-border);
310
+ transition: all var(--av-transition);
311
+ cursor: default;
312
+ }
313
+
314
+ .item-details:hover {
315
+ background: linear-gradient(90deg, var(--av-primary-light) 0%, var(--av-bg-surface) 40%);
316
+ border-left-color: var(--av-primary);
317
+ box-shadow: var(--av-shadow-sm);
318
+ }
319
+
320
+ .item-row {
321
+ width: 100%;
322
+ display: grid;
323
+ align-items: center;
324
+ padding: 14px 24px;
325
+ font-size: 14px;
326
+ color: var(--av-text-primary);
327
+ line-height: 1.5;
328
+ overflow: visible;
329
+ }
330
+
331
+ .item-row span {
332
+ transition: color var(--av-transition);
333
+ }
334
+
335
+ /* ─── Action Buttons ─── */
336
+
337
+ .action-buttons {
338
+ display: flex;
339
+ flex-direction: row;
340
+ align-items: center;
341
+ justify-content: center;
342
+ gap: 10px;
343
+ align-self: center;
344
+ padding-right: 8px;
345
+ }
346
+
347
+ .action-buttons mat-icon {
348
+ color: white !important;
349
+ font-size: 16px;
350
+ width: 16px;
351
+ height: 16px;
352
+ }
353
+
354
+ .item-action-edit {
355
+ justify-self: center;
356
+ text-align: center !important;
357
+ background: linear-gradient(135deg, var(--av-edit) 0%, #38b6db 100%) !important;
358
+ height: 34px !important;
359
+ width: 34px !important;
360
+ border-radius: 8px !important;
361
+ display: flex !important;
362
+ align-items: center !important;
363
+ justify-content: center !important;
364
+ box-shadow: 0 2px 6px rgba(76, 201, 240, 0.3) !important;
365
+ transition: all var(--av-transition) !important;
366
+ }
367
+
368
+ .item-action-edit:hover {
369
+ transform: translateY(-2px) scale(1.08) !important;
370
+ box-shadow: 0 4px 12px rgba(76, 201, 240, 0.45) !important;
371
+ filter: brightness(1.08);
372
+ }
373
+
374
+ .item-action-edit:active {
375
+ transform: translateY(0) scale(0.96) !important;
376
+ }
377
+
378
+ .item-action-delete {
379
+ text-align: center !important;
380
+ background: linear-gradient(135deg, var(--av-delete) 0%, #d63d62 100%) !important;
381
+ height: 34px !important;
382
+ width: 34px !important;
383
+ border-radius: 8px !important;
384
+ display: flex !important;
385
+ align-items: center !important;
386
+ justify-content: center !important;
387
+ box-shadow: 0 2px 6px rgba(239, 71, 111, 0.3) !important;
388
+ transition: all var(--av-transition) !important;
389
+ }
390
+
391
+ .item-action-delete:hover {
392
+ transform: translateY(-2px) scale(1.08) !important;
393
+ box-shadow: 0 4px 12px rgba(239, 71, 111, 0.45) !important;
394
+ filter: brightness(1.08);
395
+ }
396
+
397
+ .item-action-delete:active {
398
+ transform: translateY(0) scale(0.96) !important;
399
+ }
400
+
401
+ .item-action {
402
+ text-align: center !important;
403
+ background: linear-gradient(135deg, var(--av-delete) 0%, #d63d62 100%) !important;
404
+ height: 34px !important;
405
+ width: 34px !important;
406
+ border-radius: 8px !important;
407
+ display: flex !important;
408
+ align-items: center !important;
409
+ justify-content: center !important;
410
+ box-shadow: 0 2px 6px rgba(239, 71, 111, 0.3) !important;
411
+ transition: all var(--av-transition) !important;
412
+ }
413
+
414
+ .item-action:hover {
415
+ transform: translateY(-2px) scale(1.08) !important;
416
+ box-shadow: 0 4px 12px rgba(239, 71, 111, 0.45) !important;
417
+ }
418
+
419
+ /* ════════════════════════════════════════
420
+ PAGINATOR
421
+ ════════════════════════════════════════ */
422
+
423
+ .paginator-container {
424
+ margin-top: 4px;
425
+ border-radius: 0 0 var(--av-radius-md) var(--av-radius-md);
426
+ overflow: hidden;
427
+ }
428
+
429
+ .paginator-container mat-paginator {
430
+ background: var(--av-bg-muted) !important;
431
+ border-top: 1px solid var(--av-border) !important;
432
+ }
433
+
434
+ /* ════════════════════════════════════════
435
+ FILTER MENU / POPOVER — Compact Design
436
+ ════════════════════════════════════════ */
437
+
438
+ .filter-menu-panel {
439
+ min-width: 240px !important;
440
+ }
441
+
442
+ .filter-container {
443
+ padding: 12px 14px;
444
+ display: flex;
445
+ flex-direction: column;
446
+ gap: 6px;
447
+ }
448
+
449
+ .filter-rule {
450
+ display: flex;
451
+ flex-direction: column;
452
+ gap: 4px;
453
+ padding-bottom: 8px;
454
+ border-bottom: 1px dashed var(--av-border);
455
+ }
456
+
457
+ .filter-rule:last-of-type {
458
+ border-bottom: none;
459
+ padding-bottom: 0;
460
+ }
461
+
462
+ .full-width {
463
+ width: 100%;
464
+ }
465
+
466
+ /* ─── Compact Angular Material Form Fields (Filter + Search) ─── */
467
+
468
+ .compact ::ng-deep .mat-mdc-form-field-subscript-wrapper {
469
+ display: none;
470
+ }
471
+
472
+ .compact ::ng-deep .mat-mdc-text-field-wrapper {
473
+ padding: 0 10px !important;
474
+ }
475
+
476
+ .compact ::ng-deep .mat-mdc-form-field-infix {
477
+ min-height: 36px !important;
478
+ padding-top: 6px !important;
479
+ padding-bottom: 6px !important;
480
+ }
481
+
482
+ .compact ::ng-deep .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading,
483
+ .compact ::ng-deep .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__notch,
484
+ .compact ::ng-deep .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing {
485
+ border-color: var(--av-border) !important;
486
+ }
487
+
488
+ .compact ::ng-deep .mat-mdc-form-field-flex {
489
+ align-items: center;
490
+ }
491
+
492
+ .compact ::ng-deep .mat-mdc-select-trigger {
493
+ font-size: 13px;
494
+ }
495
+
496
+ .compact ::ng-deep input.mat-mdc-input-element {
497
+ font-size: 13px;
498
+ }
499
+
500
+ .compact ::ng-deep .mat-mdc-floating-label {
501
+ font-size: 13px;
502
+ }
503
+
504
+ /* ─── Global Search Compact ─── */
505
+
506
+ ::ng-deep .global-search-field input.mat-mdc-input-element {
507
+ font-size: 13px;
508
+ }
509
+
510
+ .add-rule-btn {
511
+ font-size: 12px !important;
512
+ font-weight: 600 !important;
513
+ padding: 0 !important;
514
+ height: 28px !important;
515
+ color: var(--av-primary) !important;
516
+ border-radius: var(--av-radius-sm) !important;
517
+ transition: all var(--av-transition) !important;
518
+ }
519
+
520
+ .add-rule-btn:hover {
521
+ background: var(--av-primary-light) !important;
522
+ }
523
+
524
+ .add-rule-btn mat-icon {
525
+ font-size: 14px;
526
+ width: 14px;
527
+ height: 14px;
528
+ }
529
+
530
+ .filter-actions {
531
+ display: flex;
532
+ align-items: center;
533
+ margin-top: 6px;
534
+ gap: 8px;
535
+ }
536
+
537
+ .filter-actions button {
538
+ border-radius: var(--av-radius-sm) !important;
539
+ font-weight: 600 !important;
540
+ font-size: 12px !important;
541
+ letter-spacing: 0.3px;
542
+ height: 32px !important;
543
+ line-height: 32px !important;
544
+ }
545
+
546
+ /* ════════════════════════════════════════
547
+ NO DATA STATE
548
+ ════════════════════════════════════════ */
549
+
550
+ .no-data-msg {
551
+ padding: 48px 24px;
552
+ text-align: center;
553
+ color: var(--av-text-muted);
554
+ font-size: 14px;
555
+ font-weight: 500;
556
+ font-style: normal;
557
+ background: var(--av-bg-muted);
558
+ border-radius: 0 0 var(--av-radius-md) var(--av-radius-md);
559
+ border: 1px dashed var(--av-border);
560
+ border-top: none;
561
+ margin-top: 0;
562
+ letter-spacing: 0.2px;
563
+ }
564
+
565
+ mat-form-field {
566
+ --mat-form-field-container-height: 40px !important;
567
+ --mat-form-field-container-vertical-padding: 8px !important;
568
+ }
@@ -0,0 +1,124 @@
1
+ <!-- Global Search and Clear -->
2
+ <div class="table-top-actions">
3
+ <button mat-stroked-button (click)="clearAllFilters()" class="clear-filters-btn">
4
+ <mat-icon>filter_alt_off</mat-icon> Clear
5
+ </button>
6
+ <div class="spacer"></div>
7
+ <mat-form-field appearance="outline" class="global-search-field">
8
+ <mat-icon matIconPrefix>search</mat-icon>
9
+ <mat-label>Keyboard Search</mat-label>
10
+ <input matInput [(ngModel)]="globalSearchTerm" (input)="applyAllFilters()" placeholder="Search...">
11
+ </mat-form-field>
12
+ </div>
13
+
14
+ @if (processedData.length > 0) {
15
+ <div class="item-header-row" [ngStyle]="{'grid-template-columns': gridTemplateColumns}">
16
+ @for (header of getDisplayedHeaders(); track $index) {
17
+ <div class="header-cell" [ngClass]="getHeaderFieldClasses(header)">
18
+ <div class="header-content" (click)="TableColumns[$index] ? toggleSort(TableColumns[$index].field) : null">
19
+ <strong>{{ header.label }}</strong>
20
+ @if (TableColumns[$index]) {
21
+ <mat-icon class="sort-icon" [ngClass]="{'active': sortField === TableColumns[$index].field}">
22
+ @if (sortField !== TableColumns[$index].field || sortDirection === '') {
23
+ unfold_more
24
+ } @else if (sortDirection === 'asc') {
25
+ expand_less
26
+ } @else {
27
+ expand_more
28
+ }
29
+ </mat-icon>
30
+ }
31
+ </div>
32
+
33
+ @if (TableColumns[$index]) {
34
+ <button mat-icon-button [matMenuTriggerFor]="filterMenu" class="filter-btn">
35
+ <mat-icon [class.active-filter]="hasActiveFilter(TableColumns[$index].field)">filter_list</mat-icon>
36
+ </button>
37
+
38
+ <mat-menu #filterMenu="matMenu" class="filter-menu-panel">
39
+ <div class="filter-container" (click)="$event.stopPropagation()">
40
+ <mat-form-field appearance="outline" class="full-width compact">
41
+ <mat-select [(ngModel)]="getColumnFilter(TableColumns[$index].field).matchMode">
42
+ <mat-option value="all">Match All</mat-option>
43
+ <mat-option value="any">Match Any</mat-option>
44
+ </mat-select>
45
+ </mat-form-field>
46
+
47
+ @for (rule of getColumnFilter(TableColumns[$index].field).rules; track rule; let ri = $index) {
48
+ <div class="filter-rule">
49
+ <mat-form-field appearance="outline" class="full-width compact">
50
+ <mat-select [(ngModel)]="rule.operator">
51
+ <mat-option value="starts">Starts with</mat-option>
52
+ <mat-option value="contains">Contains</mat-option>
53
+ <mat-option value="not_contains">Not contains</mat-option>
54
+ <mat-option value="ends">Ends with</mat-option>
55
+ <mat-option value="equals">Equals</mat-option>
56
+ <mat-option value="not_equals">Not equals</mat-option>
57
+ </mat-select>
58
+ </mat-form-field>
59
+ <mat-form-field appearance="outline" class="full-width compact">
60
+ <input matInput [(ngModel)]="rule.value" placeholder="Value">
61
+ </mat-form-field>
62
+ </div>
63
+ }
64
+
65
+ <button mat-button color="primary" class="add-rule-btn"
66
+ (click)="getColumnFilter(TableColumns[$index].field).rules.push({operator: 'starts', value: ''})">
67
+ <mat-icon>add</mat-icon> Add Rule
68
+ </button>
69
+
70
+ <div class="filter-actions">
71
+ <button mat-button
72
+ (click)="getColumnFilter(TableColumns[$index].field).rules = [{operator: 'starts', value: ''}]; setColumnFilter(TableColumns[$index].field, null)">Clear</button>
73
+ <div class="spacer"></div>
74
+ <button mat-flat-button color="primary"
75
+ (click)="setColumnFilter(TableColumns[$index].field, getColumnFilter(TableColumns[$index].field))">Apply</button>
76
+ </div>
77
+ </div>
78
+ </mat-menu>
79
+ }
80
+ </div>
81
+ }
82
+ </div>
83
+
84
+ <!-- Display only the paginated items -->
85
+ @for (item of getPaginatedData(); track $index) {
86
+ <mat-card>
87
+ <mat-card-content>
88
+ <div class="item-details">
89
+ <div class="item-row" [ngStyle]="{'grid-template-columns': gridTemplateColumns}">
90
+ @for (column of TableColumns; track column) {
91
+ <span [ngClass]="getDataFieldClasses(column)" [ngStyle]="{ color: getDataFiledColor(column) }">{{
92
+ getValueForColumn(item, column) }}</span>
93
+ }
94
+ @if (EnableActionColumn) {
95
+ <div class="action-buttons">
96
+ @if (EnableButtonModify) {
97
+ <button class="item-action-edit" mat-icon-button color="warn" (click)="modifyItem(getActualIndex($index))">
98
+ <mat-icon style="color:#ffffff;">edit</mat-icon>
99
+ </button>
100
+ }
101
+ @if (EnableButtonDelete) {
102
+ <button class="item-action-delete" mat-icon-button color="warn" (click)="removeItem(getActualIndex($index))">
103
+ <mat-icon style="color:#ffffff;">delete</mat-icon>
104
+ </button>
105
+ }
106
+ </div>
107
+ }
108
+ </div>
109
+ </div>
110
+ </mat-card-content>
111
+ </mat-card>
112
+ }
113
+
114
+ <!-- Move paginator outside the loop -->
115
+ <div class="paginator-container">
116
+ <mat-paginator [pageSize]="PageSize" [length]="processedData.length" [pageSizeOptions]="PageSizeOptions"
117
+ [pageIndex]="currentPage" (page)="pageChange($event)" showFirstLastButtons>
118
+ </mat-paginator>
119
+ </div>
120
+ } @else {
121
+ <div class="no-data-msg">
122
+ No items found matching your search/filters.
123
+ </div>
124
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { AvDataTable } from './av-data-table';
4
+
5
+ describe('AvDataTable', () => {
6
+ let component: AvDataTable;
7
+ let fixture: ComponentFixture<AvDataTable>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [AvDataTable]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(AvDataTable);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });