@zambon-dev/library 1.6.0 → 1.6.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/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
23
23
|
|
|
24
24
|
### ⚠ Breaking Changes / Migration
|
|
25
25
|
|
|
26
|
+
## [1.6.2] - 2026-09-20
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **A `lib-data-grid` column with no room from the start no longer drags its heading out of line.**
|
|
31
|
+
1.6.1 removes the heading of a collapsed column, but only once that column had measured a real
|
|
32
|
+
width at some point. A column that never has any room does not, so it kept a heading over nothing
|
|
33
|
+
and pushed every column to its right along -- up to 263px on a fourteen-column screen, which is
|
|
34
|
+
the same drift 1.6.1 set out to remove.
|
|
35
|
+
|
|
36
|
+
Whether a zero is believable is now settled by the row rather than by what the column measured
|
|
37
|
+
before: if the row has a width the layout is live, so a column reporting zero really has
|
|
38
|
+
collapsed.
|
|
39
|
+
|
|
40
|
+
- **`lib-data-grid` headings no longer stay behind after you revisit a tab.** Re-activating a
|
|
41
|
+
detached tab puts the grid back in the page with its horizontal scroll at the start again, and no
|
|
42
|
+
scroll event follows to say so, so the headings kept the offset they had when you left: on a grid
|
|
43
|
+
scrolled 300px every heading sat 300px away from its column. The header now reconciles with the
|
|
44
|
+
body whenever the grid is re-measured, which is what re-inserting it triggers.
|
|
45
|
+
|
|
46
|
+
## [1.6.1] - 2026-09-19
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- **`lib-data-grid` headings now sit over their own column.** On a grid with many columns each
|
|
51
|
+
heading drifted further from its cells than the last -- up to 263px on a fourteen-column screen --
|
|
52
|
+
and scrolling sideways separated them completely.
|
|
53
|
+
|
|
54
|
+
The body lays the columns out as a CSS grid inside the CDK viewport; the heading row is a flex
|
|
55
|
+
row outside it that copies each column's measured width. Four things pulled the two apart:
|
|
56
|
+
|
|
57
|
+
- The heading cells could **shrink**, so once the columns together were wider than the view every
|
|
58
|
+
heading was compressed a little and the error accumulated across the row.
|
|
59
|
+
- The heading row **did not follow the body sideways**. The rows scroll inside the viewport and
|
|
60
|
+
the headings simply stayed where they were.
|
|
61
|
+
- A column was **measured once and never again**, while the body keeps resizing its
|
|
62
|
+
`minmax(x, min-content)` columns as virtual scrolling brings different content into view.
|
|
63
|
+
- A column measured at **zero** -- a `1fr` column collapsed for want of room -- left its heading
|
|
64
|
+
with no width at all, so it kept its text width and shoved everything to its right along.
|
|
65
|
+
|
|
66
|
+
Headings are now fixed to the measured width, translate with the body's horizontal scroll, track
|
|
67
|
+
every resize, and a heading whose column has collapsed is removed rather than left taking a gap
|
|
68
|
+
the body does not have. Measured in a running application the drift is zero across every column,
|
|
69
|
+
at rest and scrolled.
|
|
70
|
+
|
|
71
|
+
A column that declares no `size` is laid out as `minmax(0, 1fr)`, which is free to collapse. If
|
|
72
|
+
one of yours does, its heading now goes with it rather than staying behind as a label over
|
|
73
|
+
nothing. Give such a column a real minimum -- `size: 'minmax(8rem, 1fr)'` -- to keep both on
|
|
74
|
+
screen.
|
|
75
|
+
|
|
26
76
|
## [1.6.0] - 2026-09-16
|
|
27
77
|
|
|
28
78
|
### Added
|
|
@@ -265,7 +315,9 @@ config options and the `getUserProfile()` method still exist but are no longer c
|
|
|
265
315
|
available via [GitHub Releases](https://github.com/RicardoZambon/ZLibraries/releases) and the
|
|
266
316
|
`library-v*` tags.
|
|
267
317
|
|
|
268
|
-
[Unreleased]: https://github.com/RicardoZambon/ZLibraries/compare/library-v1.6.
|
|
318
|
+
[Unreleased]: https://github.com/RicardoZambon/ZLibraries/compare/library-v1.6.2...HEAD
|
|
319
|
+
[1.6.2]: https://github.com/RicardoZambon/ZLibraries/releases/tag/library-v1.6.2
|
|
320
|
+
[1.6.1]: https://github.com/RicardoZambon/ZLibraries/releases/tag/library-v1.6.1
|
|
269
321
|
[1.6.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/library-v1.6.0
|
|
270
322
|
[1.5.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/library-v1.5.0
|
|
271
323
|
[1.4.1]: https://github.com/RicardoZambon/ZLibraries/releases/tag/library-v1.4.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Component, inject, Injectable, EventEmitter, InjectionToken, Input, Output, KeyValueDiffers, ViewContainerRef, TemplateRef, ElementRef, HostListener, ViewChild, ChangeDetectorRef, ChangeDetectionStrategy, NgZone, Directive, ContentChildren, Pipe, NgModule } from '@angular/core';
|
|
3
|
-
import { Subject, ReplaySubject, take, throwError, tap, map, takeUntil, filter, debounceTime, startWith, pairwise, Observable, forkJoin, switchMap, of, delay, merge } from 'rxjs';
|
|
3
|
+
import { Subject, ReplaySubject, take, throwError, tap, map, takeUntil, filter, debounceTime, startWith, pairwise, Observable, forkJoin, switchMap, of, fromEvent, delay, merge } from 'rxjs';
|
|
4
4
|
import { Overlay, OverlayPositionBuilder } from '@angular/cdk/overlay';
|
|
5
5
|
import { TemplatePortal } from '@angular/cdk/portal';
|
|
6
6
|
import * as i1 from '@angular/common';
|
|
@@ -2215,7 +2215,7 @@ class DataGridRowComponent extends BaseComponent {
|
|
|
2215
2215
|
dataGridDataset = inject(DataGridDataset);
|
|
2216
2216
|
selected = false;
|
|
2217
2217
|
_rowData;
|
|
2218
|
-
|
|
2218
|
+
elementRef = inject(ElementRef);
|
|
2219
2219
|
//#endregion
|
|
2220
2220
|
//#region Properties
|
|
2221
2221
|
get rowData() {
|
|
@@ -2224,6 +2224,9 @@ class DataGridRowComponent extends BaseComponent {
|
|
|
2224
2224
|
get columns() {
|
|
2225
2225
|
return this.dataGridDataset.columns;
|
|
2226
2226
|
}
|
|
2227
|
+
get isLaidOut() {
|
|
2228
|
+
return (this.elementRef.nativeElement?.getBoundingClientRect().width ?? 0) > 0;
|
|
2229
|
+
}
|
|
2227
2230
|
get isRowDataSelected() {
|
|
2228
2231
|
return this.dataGridDataset.isKeySelected(this.rowKey);
|
|
2229
2232
|
}
|
|
@@ -2249,16 +2252,24 @@ class DataGridRowComponent extends BaseComponent {
|
|
|
2249
2252
|
//#endregion
|
|
2250
2253
|
//#region Event handlers
|
|
2251
2254
|
onResize(colIndex, event) {
|
|
2252
|
-
if (this.isWidthSet[colIndex]) {
|
|
2253
|
-
return;
|
|
2254
|
-
}
|
|
2255
2255
|
const width = event.contentRect.width;
|
|
2256
|
-
|
|
2256
|
+
// A zero means one of two very different things. Before the grid is laid out every column
|
|
2257
|
+
// reports zero, and taking that at face value would pin every heading at zero. Once the row
|
|
2258
|
+
// itself has a width the layout is live, and a zero is then the real thing: a 1fr column
|
|
2259
|
+
// collapsed for want of room, whose heading has to collapse with it or every column to its
|
|
2260
|
+
// right sits under the wrong one. Asking the row -- rather than remembering whether this
|
|
2261
|
+
// column once measured something -- also covers a column that is born collapsed and never
|
|
2262
|
+
// measures anything else.
|
|
2263
|
+
if (width <= 0 && !this.isLaidOut) {
|
|
2257
2264
|
return;
|
|
2258
2265
|
}
|
|
2259
|
-
|
|
2266
|
+
// Reported on every change, not just the first. The body lays the columns out as a CSS grid of
|
|
2267
|
+
// minmax(x, min-content), so a column is only as wide as the content currently rendered --
|
|
2268
|
+
// which virtual scrolling keeps changing. Measuring once and latching left the header copying
|
|
2269
|
+
// a width the body no longer had, and with many columns that drift accumulated into cells
|
|
2270
|
+
// sitting under the wrong heading.
|
|
2271
|
+
if (this.columns[colIndex].realSize !== width) {
|
|
2260
2272
|
this.columns[colIndex].realSize = width;
|
|
2261
|
-
this.isWidthSet[colIndex] = true;
|
|
2262
2273
|
}
|
|
2263
2274
|
}
|
|
2264
2275
|
onResizeSelection(event) {
|
|
@@ -2329,6 +2340,7 @@ class DataGridComponent extends BaseComponent {
|
|
|
2329
2340
|
dataGridDataset = inject(DataGridDataset);
|
|
2330
2341
|
hasFailed = false;
|
|
2331
2342
|
headerRightMargin = 0;
|
|
2343
|
+
headerScrollLeft = 0;
|
|
2332
2344
|
loading = false;
|
|
2333
2345
|
bodyResized$ = new Subject();
|
|
2334
2346
|
bodyResizeObserver;
|
|
@@ -2445,6 +2457,26 @@ class DataGridComponent extends BaseComponent {
|
|
|
2445
2457
|
}
|
|
2446
2458
|
}
|
|
2447
2459
|
ngAfterViewInit() {
|
|
2460
|
+
// The rows scroll sideways inside the CDK viewport while the header sits outside it, so the
|
|
2461
|
+
// header has to be moved by hand or the headings stay behind as the cells travel. Read outside
|
|
2462
|
+
// Angular and written back inside it, because this fires for every frame of a scroll.
|
|
2463
|
+
const viewportElement = this.viewport?.elementRef?.nativeElement;
|
|
2464
|
+
if (viewportElement) {
|
|
2465
|
+
this.ngZone.runOutsideAngular(() => {
|
|
2466
|
+
fromEvent(viewportElement, 'scroll')
|
|
2467
|
+
.pipe(takeUntil(this.destroy$))
|
|
2468
|
+
.subscribe(() => {
|
|
2469
|
+
const scrollLeft = viewportElement.scrollLeft;
|
|
2470
|
+
if (this.headerScrollLeft === scrollLeft) {
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
this.ngZone.run(() => {
|
|
2474
|
+
this.headerScrollLeft = scrollLeft;
|
|
2475
|
+
this.changeDetectorRef.detectChanges();
|
|
2476
|
+
});
|
|
2477
|
+
});
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2448
2480
|
this.viewport?.renderedRangeStream
|
|
2449
2481
|
.pipe(takeUntil(this.destroy$))
|
|
2450
2482
|
.subscribe((listRange) => {
|
|
@@ -2462,6 +2494,7 @@ class DataGridComponent extends BaseComponent {
|
|
|
2462
2494
|
this.headerRightMargin = this.bodyElement.nativeElement.clientWidth - viewportWidth;
|
|
2463
2495
|
}
|
|
2464
2496
|
this.viewport?.checkViewportSize();
|
|
2497
|
+
this.syncHeaderScroll();
|
|
2465
2498
|
this.changeDetectorRef.detectChanges();
|
|
2466
2499
|
});
|
|
2467
2500
|
this.ngZone.runOutsideAngular(() => {
|
|
@@ -2493,11 +2526,20 @@ class DataGridComponent extends BaseComponent {
|
|
|
2493
2526
|
}
|
|
2494
2527
|
//#endregion
|
|
2495
2528
|
//#region Private methods
|
|
2529
|
+
syncHeaderScroll() {
|
|
2530
|
+
// Re-inserting the viewport into the DOM -- which is what re-activating a detached tab does --
|
|
2531
|
+
// puts its scroll position back to zero without firing a scroll event, so nothing tells the
|
|
2532
|
+
// header to come back with it and the headings sit at an offset the body no longer has.
|
|
2533
|
+
const scrollLeft = this.viewport?.elementRef?.nativeElement?.scrollLeft ?? 0;
|
|
2534
|
+
if (this.headerScrollLeft !== scrollLeft) {
|
|
2535
|
+
this.headerScrollLeft = scrollLeft;
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2496
2538
|
trackByFn(index, item) {
|
|
2497
2539
|
return item.key;
|
|
2498
2540
|
}
|
|
2499
2541
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: DataGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2500
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: DataGridComponent, isStandalone: true, selector: "lib-data-grid", inputs: { disabled: "disabled", lazyLoadRows: "lazyLoadRows", showButtons: "showButtons" }, host: { properties: { "class.no-borders": "showButtons" } }, viewQueries: [{ propertyName: "bodyElement", first: true, predicate: ["body"], descendants: true }, { propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"buttons\"\n*ngIf=\"showButtons\">\n <ng-content select=\"[buttons]\"></ng-content>\n</div>\n\n<div class=\"header\"\n[class.hide]=\"isHideColumns\"\n[style.padding-right.px]=\"headerRightMargin\">\n <div class=\"header-row\">\n <div *ngIf=\"isShowMultiSelect\"\n class=\"header-cell selection\"\n [ngStyle]=\"{\n 'width': selectionColWidth ? selectionColWidth : null\n }\">\n \n </div>\n \n <div *ngFor=\"let column of columns\"\n class=\"header-cell\"\n [ngStyle]=\"{\n '
|
|
2542
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: DataGridComponent, isStandalone: true, selector: "lib-data-grid", inputs: { disabled: "disabled", lazyLoadRows: "lazyLoadRows", showButtons: "showButtons" }, host: { properties: { "class.no-borders": "showButtons" } }, viewQueries: [{ propertyName: "bodyElement", first: true, predicate: ["body"], descendants: true }, { propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"buttons\"\n*ngIf=\"showButtons\">\n <ng-content select=\"[buttons]\"></ng-content>\n</div>\n\n<div class=\"header\"\n[class.hide]=\"isHideColumns\"\n[style.padding-right.px]=\"headerRightMargin\">\n <!-- Translated by however far the body is scrolled sideways. The rows scroll inside the CDK\n viewport and the header sits outside it, so without this the headings simply stay put\n while the cells move away from them. -->\n <div class=\"header-row\"\n [style.transform]=\"headerScrollLeft ? 'translateX(-' + headerScrollLeft + 'px)' : null\">\n <div *ngIf=\"isShowMultiSelect\"\n class=\"header-cell selection\"\n [ngStyle]=\"{\n 'width': selectionColWidth ? selectionColWidth : null\n }\">\n \n </div>\n \n <!-- A measured zero is a width, not the absence of one: it is a 1fr column that collapsed,\n and its heading has to collapse too. The old test read `realSize ?? 0 > 0`, which binds\n as `realSize ?? (0 > 0)` and so turned zero into no width at all.\n\n Such a heading is removed rather than merely made zero wide, because a flex item still\n takes a gap on each side while the body grid allows the collapsed track only one, and\n that spare gap pushed every heading to its right out by 16px. -->\n <div *ngFor=\"let column of columns\"\n class=\"header-cell\"\n [ngStyle]=\"{\n 'display': column.realSize === 0 ? 'none' : null,\n 'width.px': column.realSize ?? null\n }\">\n <span>{{ column.headerName | translate }}</span>\n </div>\n </div>\n</div>\n\n<div #body\nclass=\"body\"\n[style.min-height.px]=\"bodyMinHeight\">\n <cdk-virtual-scroll-viewport\n [itemSize]=\"configs.rowHeight\"\n [style.grid-template-columns]=\"gridColumns\">\n <lib-data-grid-row #row\n *cdkVirtualFor=\"let row of dataGridDataset.loadedRows; index as i; trackBy: trackByFn\"\n [disabled]=\"disabled\"\n [isFirstRow]=\"isFirstVisibleRow(i)\"\n [rowData]=\"row\"\n [style.height.px]=\"configs.rowHeight\"\n (selectionResized)=\"onSelectionResized($event)\">\n </lib-data-grid-row>\n\n <div *ngIf=\"loading\"\n class=\"loading\"\n [style.height.px]=\"configs.rowHeight\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n \n <span>\n {{ dataGridDataset.configs.loadingDisplayText ?? '' | translate }} \n </span>\n </div>\n \n <div *ngIf=\"!loading && !hasBeenLoaded && lazyLoadRows\"\n class=\"message\"\n [style.height.px]=\"configs.rowHeight\">\n <span>\n {{ messageToDisplayWhenLazyLoad | translate }}\n </span>\n </div>\n\n <ng-container *ngIf=\"!loading && hasBeenLoaded && (!hasLoadedRows || hasFailed)\">\n <div *ngIf=\"!hasFailed && !hasLoadedRows && hasMessageToDisplayWhenEmpty && shouldDisplayMessageWhenEmpty\"\n class=\"message\"\n [style.height.px]=\"configs.rowHeight\">\n <span>\n {{ messageToDisplayWhenEmpty | translate }}\n </span>\n </div>\n\n <div *ngIf=\"hasFailed\"\n class=\"message\"\n [style.height.px]=\"configs.rowHeight\">\n <span>\n <i class=\"fas fa-exclamation-triangle mr-2 text-yellow-600\"></i>{{ messageToDisplayWhenFailed | translate }}\n </span>\n </div>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n</div>", styles: [":host-context{display:flex;-webkit-user-select:none;user-select:none;flex-direction:column;overflow:hidden}:host-context:not(.no-borders){border-radius:.5rem;border-width:1px;border-color:#d1d5dbe6;--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}:host-context.no-borders .header .header-row{padding-top:.375rem;padding-bottom:.375rem}:host-context.no-borders .body lib-data-grid-row{padding-top:.25rem;padding-bottom:.25rem}.header-row,lib-data-grid-row,.loading,.message{gap:1rem;padding-left:1rem;padding-right:1rem}.header{overflow:hidden;border-bottom-width:1px;border-color:#d1d5dbe6;background-color:#e5e7eb66;font-weight:700}.header.hide{display:none}.header .header-row{display:flex;flex-direction:row;padding-top:.75rem;padding-bottom:.75rem}.header .header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.header .header-cell:not(.selection){flex:none}.body{position:relative;flex-grow:1}.body cdk-virtual-scroll-viewport{position:absolute;inset:0}.body cdk-virtual-scroll-viewport ::ng-deep .cdk-virtual-scroll-content-wrapper{display:grid;grid-template-columns:inherit}.body lib-data-grid-row{margin-top:-1px;cursor:pointer;border-top-width:1px;border-bottom-width:1px;border-color:#cbd5e180;padding-top:.5rem;padding-bottom:.5rem}.body lib-data-grid-row:nth-child(2n){background-color:#f8fafcb3}.body lib-data-grid-row:hover{background-color:#bfdbfe33}.body lib-data-grid-row.focused{z-index:1;border-color:#94a3b899}.body lib-data-grid-row.selected{position:relative;z-index:10;--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity, 1));background-color:#bfdbfe4d}.body lib-data-grid-row.selected:hover{background-color:#bfdbfe66}.body .loading,.body .message{display:flex;align-items:center;gap:.5rem;white-space:nowrap;height:2.5rem;border-bottom-width:1px;border-color:#cbd5e180;grid-column:1 / -1}.body .loading span,.body .message span{overflow:hidden;text-overflow:ellipsis}.body .loading svg{height:1.5rem;min-height:1.5rem;width:1.5rem;min-width:1.5rem}@keyframes spin{to{transform:rotate(360deg)}}.body .loading svg{animation:spin 1s linear infinite;transition-property:opacity;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.buttons{display:flex;border-top-width:1px;border-bottom-width:1px;border-color:#d1d5dbe6;padding:.25rem}\n"], dependencies: [{ kind: "component", type: DataGridRowComponent, selector: "lib-data-grid-row", inputs: ["disabled", "isFirstRow", "rowData"], outputs: ["selectionResized"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1$2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1$2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1$2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
2501
2543
|
}
|
|
2502
2544
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: DataGridComponent, decorators: [{
|
|
2503
2545
|
type: Component,
|
|
@@ -2510,7 +2552,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
|
|
|
2510
2552
|
NgStyle,
|
|
2511
2553
|
ScrollingModule,
|
|
2512
2554
|
TranslatePipe,
|
|
2513
|
-
], template: "<div class=\"buttons\"\n*ngIf=\"showButtons\">\n <ng-content select=\"[buttons]\"></ng-content>\n</div>\n\n<div class=\"header\"\n[class.hide]=\"isHideColumns\"\n[style.padding-right.px]=\"headerRightMargin\">\n <div class=\"header-row\">\n <div *ngIf=\"isShowMultiSelect\"\n class=\"header-cell selection\"\n [ngStyle]=\"{\n 'width': selectionColWidth ? selectionColWidth : null\n }\">\n \n </div>\n \n <div *ngFor=\"let column of columns\"\n class=\"header-cell\"\n [ngStyle]=\"{\n '
|
|
2555
|
+
], template: "<div class=\"buttons\"\n*ngIf=\"showButtons\">\n <ng-content select=\"[buttons]\"></ng-content>\n</div>\n\n<div class=\"header\"\n[class.hide]=\"isHideColumns\"\n[style.padding-right.px]=\"headerRightMargin\">\n <!-- Translated by however far the body is scrolled sideways. The rows scroll inside the CDK\n viewport and the header sits outside it, so without this the headings simply stay put\n while the cells move away from them. -->\n <div class=\"header-row\"\n [style.transform]=\"headerScrollLeft ? 'translateX(-' + headerScrollLeft + 'px)' : null\">\n <div *ngIf=\"isShowMultiSelect\"\n class=\"header-cell selection\"\n [ngStyle]=\"{\n 'width': selectionColWidth ? selectionColWidth : null\n }\">\n \n </div>\n \n <!-- A measured zero is a width, not the absence of one: it is a 1fr column that collapsed,\n and its heading has to collapse too. The old test read `realSize ?? 0 > 0`, which binds\n as `realSize ?? (0 > 0)` and so turned zero into no width at all.\n\n Such a heading is removed rather than merely made zero wide, because a flex item still\n takes a gap on each side while the body grid allows the collapsed track only one, and\n that spare gap pushed every heading to its right out by 16px. -->\n <div *ngFor=\"let column of columns\"\n class=\"header-cell\"\n [ngStyle]=\"{\n 'display': column.realSize === 0 ? 'none' : null,\n 'width.px': column.realSize ?? null\n }\">\n <span>{{ column.headerName | translate }}</span>\n </div>\n </div>\n</div>\n\n<div #body\nclass=\"body\"\n[style.min-height.px]=\"bodyMinHeight\">\n <cdk-virtual-scroll-viewport\n [itemSize]=\"configs.rowHeight\"\n [style.grid-template-columns]=\"gridColumns\">\n <lib-data-grid-row #row\n *cdkVirtualFor=\"let row of dataGridDataset.loadedRows; index as i; trackBy: trackByFn\"\n [disabled]=\"disabled\"\n [isFirstRow]=\"isFirstVisibleRow(i)\"\n [rowData]=\"row\"\n [style.height.px]=\"configs.rowHeight\"\n (selectionResized)=\"onSelectionResized($event)\">\n </lib-data-grid-row>\n\n <div *ngIf=\"loading\"\n class=\"loading\"\n [style.height.px]=\"configs.rowHeight\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n \n <span>\n {{ dataGridDataset.configs.loadingDisplayText ?? '' | translate }} \n </span>\n </div>\n \n <div *ngIf=\"!loading && !hasBeenLoaded && lazyLoadRows\"\n class=\"message\"\n [style.height.px]=\"configs.rowHeight\">\n <span>\n {{ messageToDisplayWhenLazyLoad | translate }}\n </span>\n </div>\n\n <ng-container *ngIf=\"!loading && hasBeenLoaded && (!hasLoadedRows || hasFailed)\">\n <div *ngIf=\"!hasFailed && !hasLoadedRows && hasMessageToDisplayWhenEmpty && shouldDisplayMessageWhenEmpty\"\n class=\"message\"\n [style.height.px]=\"configs.rowHeight\">\n <span>\n {{ messageToDisplayWhenEmpty | translate }}\n </span>\n </div>\n\n <div *ngIf=\"hasFailed\"\n class=\"message\"\n [style.height.px]=\"configs.rowHeight\">\n <span>\n <i class=\"fas fa-exclamation-triangle mr-2 text-yellow-600\"></i>{{ messageToDisplayWhenFailed | translate }}\n </span>\n </div>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n</div>", styles: [":host-context{display:flex;-webkit-user-select:none;user-select:none;flex-direction:column;overflow:hidden}:host-context:not(.no-borders){border-radius:.5rem;border-width:1px;border-color:#d1d5dbe6;--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}:host-context.no-borders .header .header-row{padding-top:.375rem;padding-bottom:.375rem}:host-context.no-borders .body lib-data-grid-row{padding-top:.25rem;padding-bottom:.25rem}.header-row,lib-data-grid-row,.loading,.message{gap:1rem;padding-left:1rem;padding-right:1rem}.header{overflow:hidden;border-bottom-width:1px;border-color:#d1d5dbe6;background-color:#e5e7eb66;font-weight:700}.header.hide{display:none}.header .header-row{display:flex;flex-direction:row;padding-top:.75rem;padding-bottom:.75rem}.header .header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.header .header-cell:not(.selection){flex:none}.body{position:relative;flex-grow:1}.body cdk-virtual-scroll-viewport{position:absolute;inset:0}.body cdk-virtual-scroll-viewport ::ng-deep .cdk-virtual-scroll-content-wrapper{display:grid;grid-template-columns:inherit}.body lib-data-grid-row{margin-top:-1px;cursor:pointer;border-top-width:1px;border-bottom-width:1px;border-color:#cbd5e180;padding-top:.5rem;padding-bottom:.5rem}.body lib-data-grid-row:nth-child(2n){background-color:#f8fafcb3}.body lib-data-grid-row:hover{background-color:#bfdbfe33}.body lib-data-grid-row.focused{z-index:1;border-color:#94a3b899}.body lib-data-grid-row.selected{position:relative;z-index:10;--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity, 1));background-color:#bfdbfe4d}.body lib-data-grid-row.selected:hover{background-color:#bfdbfe66}.body .loading,.body .message{display:flex;align-items:center;gap:.5rem;white-space:nowrap;height:2.5rem;border-bottom-width:1px;border-color:#cbd5e180;grid-column:1 / -1}.body .loading span,.body .message span{overflow:hidden;text-overflow:ellipsis}.body .loading svg{height:1.5rem;min-height:1.5rem;width:1.5rem;min-width:1.5rem}@keyframes spin{to{transform:rotate(360deg)}}.body .loading svg{animation:spin 1s linear infinite;transition-property:opacity;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.buttons{display:flex;border-top-width:1px;border-bottom-width:1px;border-color:#d1d5dbe6;padding:.25rem}\n"] }]
|
|
2514
2556
|
}], ctorParameters: () => [], propDecorators: { bodyElement: [{
|
|
2515
2557
|
type: ViewChild,
|
|
2516
2558
|
args: ['body']
|