@reforgium/data-grid 2.1.1 → 2.2.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.
@@ -1,2617 +1,2 @@
1
- import * as i0 from '@angular/core';
2
- import { input, inject, TemplateRef, Directive, booleanAttribute, contentChild, Component, numberAttribute, InjectionToken, makeEnvironmentProviders, signal, computed, effect, Injectable, viewChild, ElementRef, ChangeDetectionStrategy, output, NgZone, contentChildren, afterRenderEffect, DestroyRef, untracked } from '@angular/core';
3
- import { NgTemplateOutlet, DatePipe, DecimalPipe } from '@angular/common';
4
- import { Subscription, Subject, fromEvent, debounceTime } from 'rxjs';
5
-
6
- /**
7
- * Directive for defining type-specific cell templates in a data grid.
8
- *
9
- * This directive allows developers to create custom cell renderers for specific data types
10
- * within the data grid component. It binds a template to a type identifier, enabling
11
- * the grid to dynamically select and render the appropriate template based on a column type.
12
- *
13
- * Example usage:
14
- * ```html
15
- * <ng-template reDataGridTypeCell="date" let-data>
16
- * {{ data.value | date }}
17
- * </ng-template>
18
- * ```
19
- *
20
- * The directive captures the template reference and makes it available to the parent
21
- * data grid component for rendering cells of the specified type.
22
- */
23
- class DataGridTypeCellTemplateDirective {
24
- /**
25
- * The type identifier for this cell template.
26
- *
27
- * Specifies which data type this template should be used for.
28
- * When the data grid encounters a column with a matching type,
29
- * it will use this template to render cells in that column.
30
- *
31
- * @default ''
32
- */
33
- type = input('', { ...(ngDevMode ? { debugName: "type" } : {}), alias: 'reDataGridTypeCell' });
34
- /**
35
- * Reference to the template defined in the directive.
36
- *
37
- * This template will be rendered for each cell of the matching type,
38
- * receiving `RenderTemplateData` as its context with cell-specific information.
39
- */
40
- tpl = inject((TemplateRef));
41
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridTypeCellTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
42
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: DataGridTypeCellTemplateDirective, isStandalone: true, selector: "ng-template[reDataGridTypeCell]", inputs: { type: { classPropertyName: "type", publicName: "reDataGridTypeCell", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
43
- }
44
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridTypeCellTemplateDirective, decorators: [{
45
- type: Directive,
46
- args: [{ selector: 'ng-template[reDataGridTypeCell]' }]
47
- }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "reDataGridTypeCell", required: false }] }] } });
48
-
49
- class DataGridCellTemplateDirective {
50
- key = input('', { ...(ngDevMode ? { debugName: "key" } : {}), alias: 'reDataGridCell' });
51
- /**
52
- * The injected template reference containing the custom cell template.
53
- * The template context is of the type `DataGridCellTemplateDirective`.
54
- */
55
- tpl = inject((TemplateRef));
56
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
57
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: DataGridCellTemplateDirective, isStandalone: true, selector: "ng-template[reDataGridCell]", inputs: { key: { classPropertyName: "key", publicName: "reDataGridCell", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
58
- }
59
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellTemplateDirective, decorators: [{
60
- type: Directive,
61
- args: [{ selector: 'ng-template[reDataGridCell]' }]
62
- }], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "reDataGridCell", required: false }] }] } });
63
-
64
- /**
65
- * Directive for defining custom header templates in data grid columns.
66
- *
67
- * This directive allows you to specify a custom template for rendering column headers
68
- * in the data grid. The template is associated with a column key and receives
69
- * header-specific context data.
70
- *
71
- * @example
72
- * ```html
73
- * <ng-template reDataGridHeader="username" let-header>
74
- * <div class="custom-header">{{ header.label }}</div>
75
- * </ng-template>
76
- * ```
77
- */
78
- class DataGridHeaderTemplateDirective {
79
- /**
80
- * The column key this header template is associated with.
81
- * Uses the `reDataGridHeader` directive attribute as an alias.
82
- * Defaults to an empty string if not provided.
83
- */
84
- key = input('', { ...(ngDevMode ? { debugName: "key" } : {}), alias: 'reDataGridHeader' });
85
- /**
86
- * The injected template reference containing the custom header template.
87
- * The template context is of the type `HeaderTemplateData`.
88
- */
89
- tpl = inject((TemplateRef));
90
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridHeaderTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
91
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: DataGridHeaderTemplateDirective, isStandalone: true, selector: "ng-template[reDataGridHeader]", inputs: { key: { classPropertyName: "key", publicName: "reDataGridHeader", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
92
- }
93
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridHeaderTemplateDirective, decorators: [{
94
- type: Directive,
95
- args: [{ selector: 'ng-template[reDataGridHeader]' }]
96
- }], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "reDataGridHeader", required: false }] }] } });
97
-
98
- /**
99
- * Directive for providing a custom template for data grid rows.
100
- *
101
- * Used as a structural directive on `<ng-template>` elements within data grid components.
102
- * The template receives row data, index, columns, and layout helpers.
103
- *
104
- * Example:
105
- * ```html
106
- * <ng-template reDataGridRow let-row let-index="index">
107
- * <div class="my-row">{{ index + 1 }} - {{ row.name }}</div>
108
- * </ng-template>
109
- * ```
110
- *
111
- * Template context:
112
- * - `$implicit: Data` — row data
113
- * - `index: number` — row index
114
- * - `columns: GridColumn<Data>[]` — visible columns
115
- * - `rowHeight: number` — row height in pixels
116
- * - `isSticky: boolean` — sticky row flag
117
- */
118
- class DataGridRowDirective {
119
- tpl = inject((TemplateRef));
120
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridRowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
121
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridRowDirective, isStandalone: true, selector: "ng-template[reDataGridRow]", ngImport: i0 });
122
- }
123
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridRowDirective, decorators: [{
124
- type: Directive,
125
- args: [{ selector: 'ng-template[reDataGridRow]' }]
126
- }] });
127
-
128
- class DataGridDeclarativeHeaderDirective {
129
- tpl = inject((TemplateRef));
130
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridDeclarativeHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
131
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridDeclarativeHeaderDirective, isStandalone: true, selector: "ng-template[reHeader]", ngImport: i0 });
132
- }
133
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridDeclarativeHeaderDirective, decorators: [{
134
- type: Directive,
135
- args: [{ selector: 'ng-template[reHeader]' }]
136
- }] });
137
- class DataGridDeclarativeCellDirective {
138
- tpl = inject((TemplateRef));
139
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridDeclarativeCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
140
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridDeclarativeCellDirective, isStandalone: true, selector: "ng-template[reCell]", ngImport: i0 });
141
- }
142
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridDeclarativeCellDirective, decorators: [{
143
- type: Directive,
144
- args: [{ selector: 'ng-template[reCell]' }]
145
- }] });
146
-
147
- class DataGridDeclarativeColumn {
148
- key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
149
- header = input(undefined, ...(ngDevMode ? [{ debugName: "header" }] : []));
150
- align = input(undefined, ...(ngDevMode ? [{ debugName: "align" }] : []));
151
- sortKey = input(undefined, ...(ngDevMode ? [{ debugName: "sortKey" }] : []));
152
- sticky = input(...(ngDevMode ? [undefined, { debugName: "sticky" }] : []));
153
- expandBy = input(undefined, ...(ngDevMode ? [{ debugName: "expandBy" }] : []));
154
- disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute });
155
- visible = input(true, { ...(ngDevMode ? { debugName: "visible" } : {}), transform: booleanAttribute });
156
- width = input(undefined, { ...(ngDevMode ? { debugName: "width" } : {}), transform: toOptionalNumber });
157
- minWidth = input(undefined, { ...(ngDevMode ? { debugName: "minWidth" } : {}), transform: toOptionalNumber });
158
- maxWidth = input(undefined, { ...(ngDevMode ? { debugName: "maxWidth" } : {}), transform: toOptionalNumber });
159
- flex = input(undefined, { ...(ngDevMode ? { debugName: "flex" } : {}), transform: toOptionalNumber });
160
- type = input(undefined, ...(ngDevMode ? [{ debugName: "type" }] : []));
161
- typeParams = input(undefined, ...(ngDevMode ? [{ debugName: "typeParams" }] : []));
162
- defaultValue = input(undefined, ...(ngDevMode ? [{ debugName: "defaultValue" }] : []));
163
- value = input(undefined, ...(ngDevMode ? [{ debugName: "value" }] : []));
164
- track = input(undefined, ...(ngDevMode ? [{ debugName: "track" }] : []));
165
- tooltip = input(undefined, ...(ngDevMode ? [{ debugName: "tooltip" }] : []));
166
- headerTplRef = contentChild(DataGridDeclarativeHeaderDirective, ...(ngDevMode ? [{ debugName: "headerTplRef" }] : []));
167
- cellTplRef = contentChild(DataGridDeclarativeCellDirective, ...(ngDevMode ? [{ debugName: "cellTplRef" }] : []));
168
- toDeclarativeColumn() {
169
- return {
170
- key: this.key(),
171
- header: this.header(),
172
- headerTemplate: this.headerTplRef()?.tpl,
173
- cellTemplate: this.cellTplRef()?.tpl,
174
- align: this.align(),
175
- sortKey: this.sortKey(),
176
- sticky: this.sticky(),
177
- expandBy: this.expandBy(),
178
- disabled: this.disabled(),
179
- visible: this.visible(),
180
- width: this.width(),
181
- minWidth: this.minWidth(),
182
- maxWidth: this.maxWidth(),
183
- flex: this.flex(),
184
- type: this.type(),
185
- typeParams: this.typeParams(),
186
- defaultValue: this.defaultValue(),
187
- value: this.value(),
188
- track: this.track(),
189
- tooltip: this.tooltip(),
190
- };
191
- }
192
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridDeclarativeColumn, deps: [], target: i0.ɵɵFactoryTarget.Component });
193
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.1", type: DataGridDeclarativeColumn, isStandalone: true, selector: "re-dg-column", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, sortKey: { classPropertyName: "sortKey", publicName: "sortKey", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, expandBy: { classPropertyName: "expandBy", publicName: "expandBy", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, flex: { classPropertyName: "flex", publicName: "flex", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, typeParams: { classPropertyName: "typeParams", publicName: "typeParams", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, track: { classPropertyName: "track", publicName: "track", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "headerTplRef", first: true, predicate: DataGridDeclarativeHeaderDirective, descendants: true, isSignal: true }, { propertyName: "cellTplRef", first: true, predicate: DataGridDeclarativeCellDirective, descendants: true, isSignal: true }], ngImport: i0, template: '<ng-content />', isInline: true });
194
- }
195
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridDeclarativeColumn, decorators: [{
196
- type: Component,
197
- args: [{
198
- selector: 're-dg-column',
199
- template: '<ng-content />',
200
- }]
201
- }], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], sortKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortKey", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], expandBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandBy", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], flex: [{ type: i0.Input, args: [{ isSignal: true, alias: "flex", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], typeParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeParams", required: false }] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], track: [{ type: i0.Input, args: [{ isSignal: true, alias: "track", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], headerTplRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataGridDeclarativeHeaderDirective), { isSignal: true }] }], cellTplRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataGridDeclarativeCellDirective), { isSignal: true }] }] } });
202
- function toOptionalNumber(value) {
203
- if (value === null || value === undefined || value === '') {
204
- return undefined;
205
- }
206
- const number = numberAttribute(value);
207
- return Number.isNaN(number) ? undefined : number;
208
- }
209
-
210
- /**
211
- * Directive for providing a custom template to display when the data grid has no data.
212
- *
213
- * Used as a structural directive on `<ng-template>` elements within data grid components.
214
- * The template receives a boolean context value indicating the empty state.
215
- *
216
- * Example:
217
- * ```html
218
- * <ng-template reDataGridEmpty let-isEmpty>
219
- * <div *ngIf="isEmpty">No data available</div>
220
- * </ng-template>
221
- * ```
222
- *
223
- * Template context:
224
- * - `$implicit: boolean` — indicates whether the grid is in an empty state
225
- */
226
- class DataGridCellEmptyDirective {
227
- tpl = inject((TemplateRef));
228
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellEmptyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
229
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridCellEmptyDirective, isStandalone: true, selector: "ng-template[reDataGridEmpty]", ngImport: i0 });
230
- }
231
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellEmptyDirective, decorators: [{
232
- type: Directive,
233
- args: [{ selector: 'ng-template[reDataGridEmpty]' }]
234
- }] });
235
- /**
236
- * Directive for providing a custom template to display when the data grid is loading data.
237
- *
238
- * Used as a structural directive on `<ng-template>` elements within data grid components.
239
- * The template receives a boolean context value indicating the loading state.
240
- *
241
- * Example:
242
- * ```html
243
- * <ng-template reDataGridLoading let-isLoading>
244
- * <div *ngIf="isLoading">Loading...</div>
245
- * </ng-template>
246
- * ```
247
- *
248
- * Template context:
249
- * - `$implicit: boolean` — indicates whether the grid is in loading state
250
- */
251
- class DataGridCellLoadingDirective {
252
- tpl = inject((TemplateRef));
253
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellLoadingDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
254
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridCellLoadingDirective, isStandalone: true, selector: "ng-template[reDataGridLoading]", ngImport: i0 });
255
- }
256
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellLoadingDirective, decorators: [{
257
- type: Directive,
258
- args: [{ selector: 'ng-template[reDataGridLoading]' }]
259
- }] });
260
-
261
- /**
262
- * Directive for providing a custom template for sticky rows.
263
- *
264
- * Used as a structural directive on `<ng-template>` elements within data grid components.
265
- * The template receives row data and its index.
266
- *
267
- * Example:
268
- * ```html
269
- * <ng-template reDataGridStickyRow let-row let-index="index">
270
- * <div class="my-sticky-row">{{ index }} - {{ row.name }}</div>
271
- * </ng-template>
272
- * ```
273
- *
274
- * Template context:
275
- * - `$implicit: Data` — row data
276
- * - `index: number` — row index
277
- */
278
- class DataGridStickyRowDirective {
279
- tpl = inject((TemplateRef));
280
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridStickyRowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
281
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridStickyRowDirective, isStandalone: true, selector: "ng-template[reDataGridStickyRow]", ngImport: i0 });
282
- }
283
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridStickyRowDirective, decorators: [{
284
- type: Directive,
285
- args: [{ selector: 'ng-template[reDataGridStickyRow]' }]
286
- }] });
287
-
288
- class DataGridSortIconDirective {
289
- tpl = inject((TemplateRef));
290
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridSortIconDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
291
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridSortIconDirective, isStandalone: true, selector: "ng-template[reDataGridSortIcon]", ngImport: i0 });
292
- }
293
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridSortIconDirective, decorators: [{
294
- type: Directive,
295
- args: [{ selector: 'ng-template[reDataGridSortIcon]' }]
296
- }] });
297
- class DataGridExpanderIconDirective {
298
- tpl = inject((TemplateRef));
299
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridExpanderIconDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
300
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridExpanderIconDirective, isStandalone: true, selector: "ng-template[reDataGridExpanderIcon]", ngImport: i0 });
301
- }
302
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridExpanderIconDirective, decorators: [{
303
- type: Directive,
304
- args: [{ selector: 'ng-template[reDataGridExpanderIcon]' }]
305
- }] });
306
-
307
- const DEFAULT_DATA_GRID_DEFAULTS = {
308
- mode: 'pagination',
309
- hasIndexColumn: false,
310
- selection: { mode: 'none' },
311
- pageSize: 20,
312
- rowHeight: 40,
313
- headerHeight: 48,
314
- height: 'default',
315
- virtualBuffer: 8,
316
- loadingMode: 'spinner',
317
- pageStartFromZero: true,
318
- deferContent: true,
319
- deferHeader: false,
320
- deferPinned: false,
321
- deferCells: false,
322
- deferIcons: true,
323
- deferTooltip: false,
324
- translations: {
325
- emptyState: 'No records found',
326
- itemsPerPageLabel: 'Items per page:',
327
- nextPageLabel: 'Next page',
328
- prevPageLabel: 'Previous page',
329
- },
330
- debounce: {
331
- resize: 100,
332
- scroll: 50,
333
- },
334
- };
335
- const DATA_GRID_CONFIG = new InjectionToken('RE_DATA_GRID_DEFAULTS', {
336
- providedIn: 'root',
337
- factory: () => DEFAULT_DATA_GRID_DEFAULTS,
338
- });
339
- /**
340
- * Provides default configuration for Data Grid, overriding base settings.
341
- *
342
- * @param config Partial configuration object to be merged with current settings.
343
- * @returns EnvironmentProviders for use in application or component configuration.
344
- */
345
- function provideDataGridDefaults(config) {
346
- return makeEnvironmentProviders([
347
- {
348
- provide: DATA_GRID_CONFIG,
349
- useFactory: () => {
350
- const parent = inject(DATA_GRID_CONFIG, { optional: true, skipSelf: true });
351
- const base = parent ?? DEFAULT_DATA_GRID_DEFAULTS;
352
- return {
353
- ...base,
354
- ...config,
355
- selection: config.selection ?? base.selection,
356
- translations: { ...base.translations, ...config.translations },
357
- debounce: { ...base.debounce, ...config.debounce },
358
- };
359
- },
360
- },
361
- ]);
362
- }
363
-
364
- const GRID_INDEX_COLUMN = {
365
- key: '_index',
366
- type: 'index',
367
- align: 'center',
368
- header: '№',
369
- width: 72,
370
- sticky: 'left',
371
- };
372
- const GRID_CHECKBOX_COLUMN = {
373
- key: '_checkbox',
374
- type: 'checkbox',
375
- align: 'center',
376
- header: 'checkbox',
377
- width: 44,
378
- sticky: 'left',
379
- };
380
-
381
- /**
382
- * Calculates and distributes column widths within a container based on column configuration.
383
- *
384
- * The function implements a flexible layout algorithm that:
385
- * - Respects fixed-width columns (with `width` property set)
386
- * - Distributes remaining space among auto-sized columns based on their `flex` ratios
387
- * - Enforces `minWidth` and `maxWidth` constraints
388
- * - Uses a "water-fill" algorithm to grow columns proportionally
389
- * - Handles rounding errors to ensure total width matches container width
390
- *
391
- * @param columns - Array of column configuration objects with properties
392
- * like `visible`, `width`, `minWidth`, `maxWidth`, `flex`, and `key`
393
- * @param containerWidth - Available width in pixels for all columns
394
- * @param defaultCol - Default minimum width for auto-sized columns without explicit `minWidth`
395
- * @returns Layout result containing computed widths array, total width, and width lookup by column key
396
- *
397
- * @example
398
- * ```typescript
399
- * const result = layoutColumns(
400
- * [
401
- * { key: 'id', width: 50, visible: true },
402
- * { key: 'name', minWidth: 100, flex: 2, visible: true },
403
- * { key: 'age', minWidth: 80, flex: 1, visible: true }
404
- * ],
405
- * 800,
406
- * 100
407
- * );
408
- * // result.widths = [50, 500, 250]
409
- * // result.total = 800
410
- * // result.byKey = { id: 50, name: 500, age: 250 }
411
- * ```
412
- */
413
- function layoutColumns(columns, containerWidth, defaultCol) {
414
- const idx = visibleIndexes(columns);
415
- const { fixedIdx, autoIdx } = splitFixed(columns, idx);
416
- const fixedWidths = computeFixedWidths(columns, fixedIdx);
417
- const baseAuto = computeBaseAuto(columns, autoIdx, defaultCol);
418
- const sumFixed = sum(fixedWidths);
419
- const sumBase = sum(baseAuto.map((w) => w.width));
420
- const free = Math.max(containerWidth - sumFixed - sumBase, 0);
421
- const grownAuto = distributeFree(columns, baseAuto, free); // water-fill
422
- const widths = new Array(columns.length).fill(0);
423
- if (containerWidth <= 0) {
424
- const byKey = {};
425
- for (let i = 0; i < columns.length; i++) {
426
- // noinspection PointlessBooleanExpressionJS
427
- columns[i].visible !== false && (byKey[columns[i].key] = 0);
428
- }
429
- return { widths, total: 0, byKey };
430
- }
431
- for (const { index, width } of fixedWidths) {
432
- widths[index] = width;
433
- }
434
- for (const { index, width } of grownAuto) {
435
- widths[index] = width;
436
- }
437
- roundAndFix(columns, widths, fixedIdx, autoIdx, containerWidth);
438
- let total = 0;
439
- const byKey = {};
440
- for (const i of idx) {
441
- total += widths[i];
442
- byKey[columns[i].key] = widths[i];
443
- }
444
- return { widths, total, byKey };
445
- }
446
- /**
447
- * Filters and returns indexes of visible columns.
448
- *
449
- * A column is considered visible if its `visible` property is not explicitly set to `false`.
450
- *
451
- * @param cols - Array of column configurations
452
- * @returns Array of indexes for columns that should be displayed
453
- */
454
- function visibleIndexes(cols) {
455
- const out = [];
456
- for (let i = 0; i < cols.length; i++) {
457
- // noinspection PointlessBooleanExpressionJS
458
- cols[i].visible !== false && out.push(i);
459
- }
460
- return out;
461
- }
462
- /**
463
- * Splits visible column indexes into fixed-width and auto-sized groups.
464
- *
465
- * Fixed columns have an explicit `width` property defined.
466
- * Auto-sized columns have `width` as `undefined` and will grow to fill available space.
467
- *
468
- * @param cols - Array of column configurations
469
- * @param visibleIdx - Array of visible column indexes
470
- * @returns Object with `fixedIdx` (fixed-width column indexes) and `autoIdx` (auto-sized column indexes)
471
- */
472
- function splitFixed(cols, visibleIdx) {
473
- const fixedIdx = [];
474
- const autoIdx = [];
475
- for (const i of visibleIdx) {
476
- cols[i].width === undefined ? autoIdx.push(i) : fixedIdx.push(i);
477
- }
478
- return { fixedIdx, autoIdx };
479
- }
480
- /**
481
- * Computes actual widths for fixed-width columns, respecting min/max constraints.
482
- *
483
- * Takes the explicit `width` value and clamps it between `minWidth` and `maxWidth`.
484
- *
485
- * @param cols - Array of column configurations
486
- * @param fixedIdx - Array of fixed-width column indexes
487
- * @returns Array of objects with column index and computed width
488
- */
489
- const computeFixedWidths = (cols, fixedIdx) => fixedIdx.map((index) => {
490
- const col = cols[index];
491
- const width = clamp$1(col.width, col.minWidth, col.maxWidth);
492
- return { index, width };
493
- });
494
- /**
495
- * Computes base (minimum) widths for auto-sized columns before distribution of free space.
496
- *
497
- * Uses column's `minWidth` if specified, otherwise falls back to the default value.
498
- * The base width is clamped between `minWidth` and `maxWidth` constraints.
499
- *
500
- * @param cols - Array of column configurations
501
- * @param autoIdx - Array of auto-sized column indexes
502
- * @param def - Default minimum width to use when column's `minWidth` is not specified
503
- * @returns Array of objects with column index and base width
504
- */
505
- const computeBaseAuto = (cols, autoIdx, def) => autoIdx.map((index) => {
506
- const c = cols[index];
507
- const base = clamp$1(c.minWidth ?? def, c.minWidth, c.maxWidth);
508
- return { index, width: base };
509
- });
510
- /**
511
- * Distributes free space among auto-sized columns using a "water-fill" algorithm.
512
- *
513
- * The algorithm works iteratively:
514
- * 1. Identifies columns that can still grow (haven't reached `maxWidth`)
515
- * 2. Distributes remaining space proportionally based on each column's `flex` ratio
516
- * 3. Respects `maxWidth` constraints by capping growth
517
- * 4. Repeats until no space remains or no columns can grow further
518
- *
519
- * This ensures that columns with higher `flex` values receive proportionally more space,
520
- * while respecting all width constraints.
521
- *
522
- * @param cols - Array of column configurations
523
- * @param base - Array of column indexes with their base widths before distribution
524
- * @param free - Amount of free space (in pixels) to distribute among columns
525
- * @returns Array of objects with column index and final width after distribution
526
- */
527
- function distributeFree(cols, base, free) {
528
- if (free <= 0 || base.length === 0) {
529
- return base;
530
- }
531
- const widths = base.map((b) => ({ ...b }));
532
- let remaining = free;
533
- let growable = widths.filter((w) => widthsCanGrow(cols, w.index, w.width)).map((w) => w.index);
534
- while (remaining > 0 && growable.length > 0) {
535
- const flexSum = growable.reduce((s, i) => s + (cols[i].flex ?? 1), 0) || 1;
536
- let distributed = 0;
537
- for (const i of growable) {
538
- const rec = widths.find((w) => w.index === i);
539
- const cap = (cols[i].maxWidth ?? Infinity) - rec.width;
540
- if (cap <= 0) {
541
- continue;
542
- }
543
- const ideal = remaining * ((cols[i].flex ?? 1) / flexSum);
544
- const add = ideal < cap ? ideal : cap;
545
- if (add > 0) {
546
- rec.width += add;
547
- distributed += add;
548
- }
549
- }
550
- if (distributed <= 1e-6) {
551
- break;
552
- }
553
- remaining -= distributed;
554
- growable = widths.filter((w) => widthsCanGrow(cols, w.index, w.width)).map((w) => w.index);
555
- }
556
- return widths;
557
- }
558
- /**
559
- * Checks whether a column can grow beyond its current width.
560
- *
561
- * A column can grow if its current width is less than its `maxWidth` constraint
562
- * (or `Infinity` if no max is specified), with a small epsilon tolerance.
563
- *
564
- * @param cols - Array of column configurations
565
- * @param i - Column index to check
566
- * @param cur - Current width of the column
567
- * @returns `true` if the column can grow, `false` otherwise
568
- */
569
- function widthsCanGrow(cols, i, cur) {
570
- const max = cols[i].maxWidth ?? Infinity;
571
- return cur < max - 1e-6;
572
- }
573
- /**
574
- * Rounds auto-sized column widths to integers and distributes any remaining pixels to match container width exactly.
575
- *
576
- * This function handles rounding errors that occur when distributing fractional widths:
577
- * 1. Floors all auto-sized column widths to integers
578
- * 2. Calculates how many pixels are needed to reach the exact container width
579
- * 3. Distributes remaining pixels one-by-one to columns (right-to-left) that haven't reached their `maxWidth`
580
- *
581
- * Fixed-width columns are not modified. This ensures the total width matches the container precisely.
582
- *
583
- * @param cols - Array of column configurations
584
- * @param widths - Array of column widths to be modified in place
585
- * @param fixedIdx - Array of fixed-width column indexes (not modified)
586
- * @param autoIdx - Array of auto-sized column indexes (will be rounded and adjusted)
587
- * @param containerWidth - Target total width that must be matched exactly
588
- */
589
- function roundAndFix(cols, widths, fixedIdx, autoIdx, containerWidth) {
590
- const sumFixed = fixedIdx.reduce((s, i) => s + widths[i], 0);
591
- let sumAuto = 0;
592
- for (const i of autoIdx) {
593
- widths[i] = Math.floor(widths[i]);
594
- sumAuto += widths[i];
595
- }
596
- let need = Math.round(Math.max(containerWidth - sumFixed - sumAuto, 0));
597
- if (need === 0) {
598
- return;
599
- }
600
- for (let k = autoIdx.length - 1; k >= 0 && need > 0; k--) {
601
- const i = autoIdx[k];
602
- const max = cols[i].maxWidth ?? Infinity;
603
- if (widths[i] + 1 <= max) {
604
- widths[i] += 1;
605
- need--;
606
- }
607
- }
608
- }
609
- /**
610
- * Clamps a numeric value between optional minimum and maximum bounds.
611
- *
612
- * If `min` is provided and the value is less than it, returns `min`.
613
- * If `max` is provided and the value is greater than it, returns `max`.
614
- * Otherwise, returns the original value.
615
- *
616
- * @param v - Value to clamp
617
- * @param min - Optional minimum bound
618
- * @param max - Optional maximum bound
619
- * @returns Clamped value
620
- */
621
- function clamp$1(v, min, max) {
622
- min != null && v < min && (v = min);
623
- max != null && v > max && (v = max);
624
- return v;
625
- }
626
- /**
627
- * Calculates the sum of numeric values or width properties in an array.
628
- *
629
- * Supports two input formats:
630
- * - Array of numbers: sums all numeric values
631
- * - Array of objects with `width` property: sums all `width` values
632
- *
633
- * @param items - Array of numbers or objects with `width` property
634
- * @returns Sum of all values
635
- */
636
- function sum(items) {
637
- if (Array.isArray(items) && typeof items[0] === 'number') {
638
- return items.reduce((s, x) => s + x, 0);
639
- }
640
- return items.reduce((s, x) => s + x.width, 0);
641
- }
642
-
643
- // noinspection ES6PreferShortImport
644
- const DEFAULT_COLUMN_WIDTH = 140;
645
- /**
646
- * Computes and normalizes header groups based on the provided headers and columns.
647
- *
648
- * @param {GridHeaderGroup<Data>[]} headers - An array of header group objects representing the grouping information
649
- * for the grid.
650
- * @param {GridColumn<Data>[]} columns - An array of column definitions describing the columns in the grid.
651
- * @return {NormalizedHeader[]} An array of normalized header objects, where each object contains information about
652
- * the computed header ranges, widths, and keys.
653
- */
654
- function computeHeaderGroups(headers = [], columns = []) {
655
- if (!columns.length || !headers.length) {
656
- return [];
657
- }
658
- const keyToIndex = new Map(columns.map((col, index) => [col.key, index]));
659
- const columnWidths = columns.map(resolveColumnWidth);
660
- const prefix = buildWidthesPrefixSums(columnWidths);
661
- const ranges = [];
662
- const occupied = new Set();
663
- for (const header of headers) {
664
- const start = keyToIndex.get(header.from);
665
- const resolvedTo = header.to ?? header.from;
666
- const end = keyToIndex.get(resolvedTo);
667
- if (start === undefined || end === undefined) {
668
- continue;
669
- }
670
- const rangeStart = Math.min(start, end);
671
- const rangeEnd = Math.max(start, end);
672
- if (hasOverlap(rangeStart, rangeEnd, occupied)) {
673
- continue;
674
- }
675
- for (let i = rangeStart; i <= rangeEnd; i++) {
676
- occupied.add(i);
677
- }
678
- ranges.push({ header, start: rangeStart, end: rangeEnd });
679
- }
680
- const rangesByStart = new Map(ranges.map((range) => [range.start, range]));
681
- const normalized = [];
682
- for (let index = 0; index < columns.length;) {
683
- const range = rangesByStart.get(index);
684
- if (range) {
685
- normalized.push(normalizeRange(range, prefix, columns));
686
- index = range.end + 1;
687
- continue;
688
- }
689
- const start = index;
690
- while (index < columns.length && !rangesByStart.has(index)) {
691
- index++;
692
- }
693
- const end = index - 1;
694
- normalized.push({
695
- key: `_rest_${columns[start].key}_${columns[end].key}`,
696
- widthPx: sumByRange(prefix, start, end),
697
- startKey: columns[start]?.key,
698
- endKey: columns[end]?.key,
699
- });
700
- }
701
- return normalized;
702
- }
703
- function normalizeRange(range, prefix, columns) {
704
- const base = {
705
- key: range.header.key,
706
- widthPx: sumByRange(prefix, range.start, range.end),
707
- startKey: columns[range.start]?.key,
708
- endKey: columns[range.end]?.key,
709
- };
710
- if ('titleTemplate' in range.header) {
711
- base.titleTemplate = range.header.titleTemplate;
712
- return base;
713
- }
714
- base.title = range.header.title;
715
- base.align = range.header.align;
716
- return base;
717
- }
718
- function resolveColumnWidth(column) {
719
- const width = asFiniteNumber(column.width);
720
- const minWidth = asFiniteNumber(column.minWidth);
721
- const maxWidth = asFiniteNumber(column.maxWidth);
722
- let result = width ?? minWidth ?? DEFAULT_COLUMN_WIDTH;
723
- if (minWidth !== null && result < minWidth) {
724
- result = minWidth;
725
- }
726
- if (maxWidth !== null && result > maxWidth) {
727
- result = maxWidth;
728
- }
729
- return Math.max(0, Math.round(result));
730
- }
731
- function asFiniteNumber(value) {
732
- return typeof value === 'number' && Number.isFinite(value) ? value : null;
733
- }
734
- function hasOverlap(start, end, occupied) {
735
- for (let i = start; i <= end; i++) {
736
- if (occupied.has(i)) {
737
- return true;
738
- }
739
- }
740
- return false;
741
- }
742
- function buildWidthesPrefixSums(values) {
743
- const prefix = new Array(values.length + 1).fill(0);
744
- for (let i = 0; i < values.length; i++) {
745
- prefix[i + 1] = prefix[i] + values[i];
746
- }
747
- return prefix;
748
- }
749
- function sumByRange(prefix, start, end) {
750
- return prefix[end + 1] - prefix[start];
751
- }
752
-
753
- /**
754
- * Calculates the visual state of an overlay scrollbar. All arguments are raw DOM numbers.
755
- * Returns a state describing the visibility, size, and position of the thumb.
756
- */
757
- function computeScrollbarState(scrollHeight = 0, clientHeight = 0, scrollTop = 0, minThumb = 24) {
758
- const safeClient = toSafe(clientHeight);
759
- const safeScrollH = toSafe(scrollHeight);
760
- const safeTop = clamp(scrollTop, 0, Math.max(0, safeScrollH - safeClient));
761
- if (safeClient <= 0 || !isFinite(safeClient)) {
762
- return hiddenState();
763
- }
764
- if (safeScrollH <= safeClient + 1) {
765
- return hiddenState(safeClient);
766
- }
767
- const track = safeClient;
768
- const ratio = track / safeScrollH;
769
- const thumb = Math.max(minThumb, Math.floor(track * ratio));
770
- const maxScrollTop = Math.max(1, safeScrollH - track);
771
- const maxThumbTop = Math.max(1, track - thumb);
772
- const topRaw = Math.round((safeTop / maxScrollTop) * maxThumbTop);
773
- const thumbTop = clamp(isFinite(topRaw) ? topRaw : 0, 0, maxThumbTop);
774
- return {
775
- visible: true,
776
- thumbHeight: thumb,
777
- thumbTop,
778
- track,
779
- maxThumbTop,
780
- maxScrollTop,
781
- };
782
- }
783
- /** Converts thumb position thumbTop (0..maxThumbTop) to scroll position scrollTop (0..maxScrollTop) */
784
- function mapThumbTopToScrollTop(thumbTop, maxThumbTop, maxScrollTop) {
785
- const mt = Math.max(1, toSafe(maxThumbTop));
786
- const ms = Math.max(1, toSafe(maxScrollTop));
787
- const tt = clamp(toSafe(thumbTop), 0, mt);
788
- return (tt / mt) * ms;
789
- }
790
- /** Clamps the new thumb position within bounds 0..maxThumbTop */
791
- function clampThumbTop(value, maxThumbTop) {
792
- const mt = Math.max(1, toSafe(maxThumbTop));
793
- return clamp(toSafe(value), 0, mt);
794
- }
795
- function hiddenState(track = 0) {
796
- return {
797
- visible: false,
798
- thumbHeight: 0,
799
- thumbTop: 0,
800
- track,
801
- maxThumbTop: 1,
802
- maxScrollTop: 1,
803
- };
804
- }
805
- function toSafe(n) {
806
- return Number.isFinite(n) ? n : 0;
807
- }
808
- function clamp(v, min, max) {
809
- if (v < min) {
810
- return min;
811
- }
812
- if (v > max) {
813
- return max;
814
- }
815
- return v;
816
- }
817
-
818
- /**
819
- * Detects the primary scroll direction of an HTML element.
820
- *
821
- * Compares the current scroll position with the previous one to determine
822
- * whether the user is scrolling horizontally, vertically, or not at all.
823
- *
824
- * Example:
825
- * ```typescript
826
- * const detector = new ScrollDirectionDetector(scrollableDiv);
827
- *
828
- * scrollableDiv.addEventListener('scroll', () => {
829
- * const direction = detector.detect();
830
- * console.log('Scroll direction:', direction); // 'horizontal' | 'vertical' | 'none'
831
- * });
832
- * ```
833
- *
834
- * The detector stores the previous scroll position internally and updates it
835
- * on each `detect()` call to track movement deltas.
836
- */
837
- class ScrollDirectionDetector {
838
- el;
839
- /**
840
- * Previously recorded vertical scroll position (scrollTop).
841
- * @private
842
- */
843
- #prevTop = 0;
844
- /**
845
- * Previously recorded horizontal scroll position (scrollLeft).
846
- * @private
847
- */
848
- #prevLeft = 0;
849
- /**
850
- * Creates a new scroll direction detector for the given HTML element.
851
- *
852
- * @param el - The HTML element whose scroll direction will be tracked.
853
- * The element must be scrollable (have overflow content).
854
- */
855
- constructor(el) {
856
- this.el = el;
857
- this.#prevTop = el.scrollTop;
858
- this.#prevLeft = el.scrollLeft;
859
- }
860
- /**
861
- * Detects the primary scroll direction based on position changes since the last call.
862
- *
863
- * Compares the absolute deltas of horizontal and vertical scroll positions.
864
- * The direction with the greater delta is considered the primary scroll direction.
865
- *
866
- * @returns The detected scroll direction:
867
- * - `'horizontal'` if horizontal movement is greater
868
- * - `'vertical'` if vertical movement is greater
869
- * - `'none'` if no scroll movement occurred or deltas are equal
870
- */
871
- detect() {
872
- const { scrollTop, scrollLeft } = this.el;
873
- const deltaX = Math.abs(scrollLeft - this.#prevLeft);
874
- const deltaY = Math.abs(scrollTop - this.#prevTop);
875
- this.#prevTop = scrollTop;
876
- this.#prevLeft = scrollLeft;
877
- if (deltaX === 0 && deltaY === 0)
878
- return 'none';
879
- if (deltaX > deltaY)
880
- return 'horizontal';
881
- if (deltaY > deltaX)
882
- return 'vertical';
883
- return 'none';
884
- }
885
- }
886
-
887
- /**
888
- * Splits an array of grid columns into sticky left, sticky right, and all visible columns.
889
- *
890
- * This function filters columns by visibility, then divides them at the midpoint
891
- * to identify which sticky columns should be pinned to the left versus right side
892
- * of the data grid.
893
- *
894
- * @template Data - The data type extending `AnyDict` that the grid columns are based on.
895
- * @param cols - Array of grid columns to be split.
896
- * @returns An object containing:
897
- * - `left`: Array of sticky columns from the first half of visible columns.
898
- * - `right`: Array of sticky columns from the second half of visible columns.
899
- * - `visible`: Array of all visible columns (filtered by `visible !== false`).
900
- *
901
- * @example
902
- * ```typescript
903
- * const columns: GridColumn<User>[] = [...];
904
- * const { left, right, visible } = splitSticky(columns);
905
- * ```
906
- */
907
- function splitSticky(cols) {
908
- const visible = cols.filter((c) => c.visible !== false);
909
- const left = visible.filter((col) => col.sticky === 'left' || col.sticky === true);
910
- const right = visible.filter((col) => col.sticky === 'right');
911
- return { left, right, visible };
912
- }
913
-
914
- /**
915
- * View model for the data grid component.
916
- *
917
- * Manages grid state including column layout, sticky positioning, scrollbar calculations,
918
- * and pinned rows. Automatically recomputes column widths based on container size and
919
- * handles sticky column offsets for left and right pinned columns.
920
- *
921
- * @template Data - Type of data objects in the grid, must extend AnyDict
922
- *
923
- * @example
924
- * ```typescript
925
- * const gridVm = inject(DataGridVm<MyDataType>);
926
- * gridVm.columns.set([{ key: 'name', title: 'Name' }]);
927
- * gridVm.containerWidth.set(800);
928
- * ```
929
- */
930
- class DataGridVm {
931
- /**
932
- * Reference to the scrollable container element.
933
- *
934
- * Used for scrollbar calculations and scroll position management.
935
- */
936
- scrollEl = signal(undefined, ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
937
- /**
938
- * Array of column configurations for the grid.
939
- *
940
- * Defines all columns including their keys, titles, sticky positioning, and widths.
941
- * Value is reactive and triggers column layout recalculation when changed.
942
- */
943
- columns = signal([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
944
- /**
945
- * Array of pinned row configurations.
946
- *
947
- * Defines rows that remain fixed at the top or bottom of the grid during scrolling.
948
- * Each row includes data, position ('top' or 'bottom'), and optional ordering.
949
- */
950
- pinnedRows = signal([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
951
- headerGroups = signal([], ...(ngDevMode ? [{ debugName: "headerGroups" }] : []));
952
- /**
953
- * Current width of the grid container in pixels.
954
- *
955
- * Used for column width calculations and layout adjustments.
956
- * Value is reactive and triggers column layout recalculation when changed.
957
- */
958
- containerWidth = signal(0, ...(ngDevMode ? [{ debugName: "containerWidth" }] : []));
959
- /**
960
- * Flag indicating whether the custom scrollbar should be visible.
961
- *
962
- * Automatically computed based on content height vs. container height.
963
- */
964
- scrollbarVisible = signal(false, ...(ngDevMode ? [{ debugName: "scrollbarVisible" }] : []));
965
- /**
966
- * Height of the scrollbar thumb in pixels.
967
- *
968
- * Proportional to the ratio of visible content to total content height.
969
- */
970
- thumbHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbHeightPx" }] : []));
971
- /**
972
- * Top position of the scrollbar thumb in pixels.
973
- *
974
- * Corresponds to the current scroll position within the scrollable area.
975
- */
976
- thumbTopPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbTopPx" }] : []));
977
- /**
978
- * Flag indicating whether the user is currently dragging the scrollbar thumb.
979
- *
980
- * Used to track active scroll drag interactions.
981
- */
982
- dragging = false;
983
- /**
984
- * Map of global cell renderer templates by type.
985
- *
986
- * Stores reusable template references for different cell renderer types
987
- * that can be shared across multiple columns.
988
- */
989
- globalTypeCellTpls = new Map();
990
- globalDataCellTpls = new Map();
991
- globalRowCellTpls = new Map();
992
- #byKey = signal({}, ...(ngDevMode ? [{ debugName: "#byKey" }] : []));
993
- #defaultColWidth = 140;
994
- #stickyLeftMap = new Map();
995
- #stickyRightMap = new Map();
996
- #stickySplit = computed(() => splitSticky(this.columns() ?? []), ...(ngDevMode ? [{ debugName: "#stickySplit" }] : []));
997
- #layoutSignature = '';
998
- #stickySignature = '';
999
- pinnedTop = signal([], ...(ngDevMode ? [{ debugName: "pinnedTop" }] : []));
1000
- pinnedBottom = signal([], ...(ngDevMode ? [{ debugName: "pinnedBottom" }] : []));
1001
- /**
1002
- * Computed an array of non-sticky columns to display in the scrollable area.
1003
- *
1004
- * Automatically splits columns into left-sticky, visible, and right-sticky groups,
1005
- * recomputes sticky offsets, and returns only the scrollable middle section.
1006
- * Recalculates whenever columns or container width changes.
1007
- */
1008
- columnsToShow = computed(() => {
1009
- this.containerWidth();
1010
- return this.#stickySplit().visible;
1011
- }, ...(ngDevMode ? [{ debugName: "columnsToShow" }] : []));
1012
- contentWidth = computed(() => {
1013
- const columns = this.columnsToShow();
1014
- if (!columns.length) {
1015
- return 0;
1016
- }
1017
- return columns.reduce((sum, col) => sum + this.widthByKey(col.key), 0);
1018
- }, ...(ngDevMode ? [{ debugName: "contentWidth" }] : []));
1019
- /**
1020
- * Computed array of normalized header groups with calculated widths.
1021
- *
1022
- * Transforms raw header group configurations into normalized structures
1023
- * that include computed column widths for layout rendering. Returns an empty
1024
- * array if no headers or columns are configured. Recalculates whenever
1025
- * header groups or visible columns change.
1026
- *
1027
- * @returns Array of normalized header configurations with width calculations
1028
- */
1029
- normalizedHeaderGroups = computed(() => {
1030
- const headers = this.headerGroups();
1031
- const columns = this.columnsToShow();
1032
- if (!headers.length || !columns.length) {
1033
- return [];
1034
- }
1035
- const normalizedColumns = columns.map((col) => ({
1036
- ...col,
1037
- width: this.widthByKey(col.key),
1038
- }));
1039
- return computeHeaderGroups(headers, normalizedColumns);
1040
- }, ...(ngDevMode ? [{ debugName: "normalizedHeaderGroups" }] : []));
1041
- constructor() {
1042
- effect(() => {
1043
- const rows = this.pinnedRows() ?? [];
1044
- this.pinnedTop.set(rows.filter((r) => r.position === 'top').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)));
1045
- this.pinnedBottom.set(rows.filter((r) => r.position === 'bottom').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)));
1046
- });
1047
- effect(() => {
1048
- const cols = this.columns();
1049
- const width = this.containerWidth();
1050
- if (!cols.length || !width) {
1051
- return;
1052
- }
1053
- const signature = this.layoutSignature(cols, width);
1054
- if (signature === this.#layoutSignature) {
1055
- return;
1056
- }
1057
- this.#layoutSignature = signature;
1058
- const res = layoutColumns(cols, width, this.#defaultColWidth);
1059
- this.#byKey.set(res.byKey);
1060
- });
1061
- effect(() => {
1062
- this.#byKey();
1063
- const { left, right } = this.#stickySplit();
1064
- const signature = this.stickySignature(left, right);
1065
- if (signature === this.#stickySignature) {
1066
- return;
1067
- }
1068
- this.#stickySignature = signature;
1069
- this.recomputeStickyOffsets(left, right);
1070
- });
1071
- }
1072
- /**
1073
- * Returns the computed width for a column by its key.
1074
- *
1075
- * If the column width has not been calculated, returns the default column width.
1076
- *
1077
- * @param key - The unique identifier for the column
1078
- * @returns Width in pixels
1079
- */
1080
- widthByKey = (key) => this.#byKey()[key] ?? this.#defaultColWidth;
1081
- /**
1082
- * Checks if a column is pinned to the left side of the grid.
1083
- *
1084
- * @param key - The unique identifier for the column
1085
- * @returns `true` if the column is sticky on the left, `false` otherwise
1086
- */
1087
- isStickyLeft = (key) => this.#stickyLeftMap.has(key);
1088
- /**
1089
- * Checks if a column is pinned to the right side of the grid.
1090
- *
1091
- * @param key - The unique identifier for the column
1092
- * @returns `true` if the column is sticky on the right, `false` otherwise
1093
- */
1094
- isStickyRight = (key) => this.#stickyRightMap.has(key);
1095
- /**
1096
- * Returns the horizontal offset for a sticky column.
1097
- *
1098
- * Calculates the distance from the specified edge (left or right) where the column
1099
- * should be positioned. Returns `null` if the column is not sticky in the given direction.
1100
- *
1101
- * @param key - The unique identifier for the column
1102
- * @param dir - The direction to check ('left' or 'right')
1103
- * @returns Offset in pixels, or `null` if not sticky in the specified direction
1104
- */
1105
- stickyOffset = (key, dir) => dir === 'left' && this.isStickyLeft(key)
1106
- ? (this.#stickyLeftMap.get(key) ?? null)
1107
- : dir === 'right' && this.isStickyRight(key)
1108
- ? (this.#stickyRightMap.get(key) ?? null)
1109
- : null;
1110
- /**
1111
- * Calculates and updates scrollbar state based on the current scroll position.
1112
- *
1113
- * Computes whether the scrollbar should be visible, and if so, determines
1114
- * the thumb height and position based on scroll height, client height, and scroll position.
1115
- * Updates the corresponding signal properties with the calculated values.
1116
- */
1117
- calcScrollbar() {
1118
- const el = this.scrollEl()?.nativeElement;
1119
- if (!el)
1120
- return;
1121
- const state = computeScrollbarState(el.scrollHeight, el.clientHeight, el.scrollTop);
1122
- if (!state.visible) {
1123
- this.scrollbarVisible.set(false);
1124
- this.thumbHeightPx.set(0);
1125
- this.thumbTopPx.set(0);
1126
- return;
1127
- }
1128
- this.thumbHeightPx.set(state.thumbHeight);
1129
- this.thumbTopPx.set(state.thumbTop);
1130
- }
1131
- recomputeStickyOffsets(leftCols, rightCols) {
1132
- let acc = 0;
1133
- this.#stickyLeftMap.clear();
1134
- for (const col of leftCols) {
1135
- this.#stickyLeftMap.set(col.key, acc);
1136
- acc += this.widthByKey(col.key);
1137
- }
1138
- acc = 0;
1139
- this.#stickyRightMap.clear();
1140
- for (let i = rightCols.length - 1; i >= 0; i--) {
1141
- const col = rightCols[i];
1142
- this.#stickyRightMap.set(col.key, acc);
1143
- acc += this.widthByKey(col.key);
1144
- }
1145
- }
1146
- layoutSignature(cols, width) {
1147
- const parts = [`w:${width}`];
1148
- for (const col of cols) {
1149
- const anyCol = col;
1150
- const key = String(col.key);
1151
- const widthVal = anyCol['width'] ?? '';
1152
- const min = anyCol['minWidth'] ?? '';
1153
- const max = anyCol['maxWidth'] ?? '';
1154
- const flex = anyCol['flex'] ?? '';
1155
- const visible = anyCol['visible'] ?? '';
1156
- const sticky = anyCol['sticky'] ?? '';
1157
- parts.push([key, widthVal, min, max, flex, visible, sticky].join('|'));
1158
- }
1159
- return parts.join(';');
1160
- }
1161
- stickySignature(leftCols, rightCols) {
1162
- const left = leftCols.map((col) => `${col.key}:${this.widthByKey(col.key)}`).join(',');
1163
- const right = rightCols.map((col) => `${col.key}:${this.widthByKey(col.key)}`).join(',');
1164
- return `l:${left}|r:${right}`;
1165
- }
1166
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1167
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm });
1168
- }
1169
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm, decorators: [{
1170
- type: Injectable
1171
- }], ctorParameters: () => [] });
1172
-
1173
- // noinspection ES6PreferShortImport
1174
- /**
1175
- * Component for rendering individual data grid cells.
1176
- *
1177
- * Handles different cell rendering strategies based on column configuration:
1178
- * - Custom templates via `renderTemplate`
1179
- * - Global type-specific templates registered in DataGridVm
1180
- * - Built-in formatters for dates and numbers
1181
- * - Index display (1-based row numbering)
1182
- * - Plain text for simple values
1183
- *
1184
- * The component automatically determines the appropriate rendering method
1185
- * based on column properties and applies Angular pipes when needed.
1186
- *
1187
- * @template Data - Type of data objects in the grid row
1188
- *
1189
- * @example
1190
- * ```html
1191
- * <re-data-grid-cell
1192
- * [index]="0"
1193
- * [item]="rowData"
1194
- * [column]="columnConfig"
1195
- * />
1196
- * ```
1197
- */
1198
- class DataGridCellComponent {
1199
- /**
1200
- * Zero-based index of the current row in the data grid.
1201
- *
1202
- * Used for rendering row numbers (displayed as 1-based in 'index' type columns)
1203
- * and passed to custom templates as context.
1204
- */
1205
- index = input.required(...(ngDevMode ? [{ debugName: "index" }] : []));
1206
- /**
1207
- * Data object for the current row.
1208
- *
1209
- * Contains the complete row data that can be accessed by column value functions
1210
- * or custom render templates. Type-safe, according to the Data generic parameter.
1211
- */
1212
- item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
1213
- /**
1214
- * Column configuration object.
1215
- *
1216
- * Defines how the cell should be rendered, including key mapping, type,
1217
- * custom templates, or value transformation functions.
1218
- */
1219
- column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
1220
- /**
1221
- * Injected DataGridVm service instance.
1222
- *
1223
- * Provides access to global type-specific cell templates registered
1224
- * at the grid level via the ` globalTypeCellTpls ` map.
1225
- */
1226
- vm = inject(DataGridVm);
1227
- /**
1228
- * Computed rendering strategy for the current cell.
1229
- *
1230
- * Determines which template block to use based on column configuration:
1231
- * - `'tpl'` - Custom column template (`renderTemplate` property exists)
1232
- * - `'globalTypeTpl'` - Global type template (registered in DataGridVm)
1233
- * - `'date'`, `'number'`, `'index'` - Built-in formatters
1234
- * - `'plain'` - Default text rendering
1235
- *
1236
- * The value is reactive and updates when the column configuration changes.
1237
- */
1238
- type = computed(() => {
1239
- const col = this.column();
1240
- if ('renderTemplate' in col) {
1241
- return 'tpl';
1242
- }
1243
- if ('type' in col && this.vm.globalTypeCellTpls.has(col.type)) {
1244
- return 'globalTypeTpl';
1245
- }
1246
- if (this.vm.globalDataCellTpls.has(col.key)) {
1247
- return 'globalDataTpl';
1248
- }
1249
- if (this.vm.globalRowCellTpls.has(col.key)) {
1250
- return 'globalRowTpl';
1251
- }
1252
- return 'type' in col ? col['type'] : 'plain';
1253
- }, ...(ngDevMode ? [{ debugName: "type" }] : []));
1254
- /**
1255
- * Computed cell value extracted from row data.
1256
- *
1257
- * Returns the cell's display value by either:
1258
- * - Calling the `value` function from column configuration (if defined)
1259
- * - Directly accessing the row property using the column's `key`
1260
- *
1261
- * The value is reactive and updates when row data or column configuration changes.
1262
- * Used as input for templates, pipes, and default text rendering.
1263
- */
1264
- value = computed(() => {
1265
- const col = this.column();
1266
- const row = this.item();
1267
- const rawValue = 'value' in col ? col.value(row) : row[col.key];
1268
- if ('value' in col || 'renderTemplate' in col) {
1269
- return rawValue;
1270
- }
1271
- if (rawValue === null || rawValue === undefined) {
1272
- return col.defaultValue ?? rawValue;
1273
- }
1274
- return rawValue;
1275
- }, ...(ngDevMode ? [{ debugName: "value" }] : []));
1276
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1277
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DataGridCellComponent, isStandalone: true, selector: "re-data-grid-cell", inputs: { index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: true, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
1278
- @let row = item();
1279
- @let col = $any(column());
1280
- @let val = value();
1281
-
1282
- @switch (type()) {
1283
- @case ('tpl') {
1284
- <ng-container
1285
- [ngTemplateOutlet]="col.renderTemplate"
1286
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1287
- />
1288
- }
1289
- @case ('globalTypeTpl') {
1290
- <ng-container
1291
- [ngTemplateOutlet]="vm.globalTypeCellTpls.get(col.type)"
1292
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1293
- />
1294
- }
1295
- @case ('globalDataTpl') {
1296
- <ng-container
1297
- [ngTemplateOutlet]="vm.globalDataCellTpls.get(col.key)"
1298
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1299
- />
1300
- }
1301
- @case ('globalRowTpl') {
1302
- <ng-container
1303
- [ngTemplateOutlet]="vm.globalRowCellTpls.get(col.key)"
1304
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1305
- />
1306
- }
1307
- @case ('date') {
1308
- {{ val | date: col?.typeParams }}
1309
- }
1310
- @case ('number') {
1311
- {{ val | number: col?.typeParams }}
1312
- }
1313
- @case ('index') {
1314
- {{ index() + 1 }}
1315
- }
1316
- @default {
1317
- {{ val }}
1318
- }
1319
- }
1320
- `, isInline: true, styles: [":host{width:100%;text-align:inherit}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: DecimalPipe, name: "number" }] });
1321
- }
1322
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellComponent, decorators: [{
1323
- type: Component,
1324
- args: [{ selector: 're-data-grid-cell', template: `
1325
- @let row = item();
1326
- @let col = $any(column());
1327
- @let val = value();
1328
-
1329
- @switch (type()) {
1330
- @case ('tpl') {
1331
- <ng-container
1332
- [ngTemplateOutlet]="col.renderTemplate"
1333
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1334
- />
1335
- }
1336
- @case ('globalTypeTpl') {
1337
- <ng-container
1338
- [ngTemplateOutlet]="vm.globalTypeCellTpls.get(col.type)"
1339
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1340
- />
1341
- }
1342
- @case ('globalDataTpl') {
1343
- <ng-container
1344
- [ngTemplateOutlet]="vm.globalDataCellTpls.get(col.key)"
1345
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1346
- />
1347
- }
1348
- @case ('globalRowTpl') {
1349
- <ng-container
1350
- [ngTemplateOutlet]="vm.globalRowCellTpls.get(col.key)"
1351
- [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1352
- />
1353
- }
1354
- @case ('date') {
1355
- {{ val | date: col?.typeParams }}
1356
- }
1357
- @case ('number') {
1358
- {{ val | number: col?.typeParams }}
1359
- }
1360
- @case ('index') {
1361
- {{ index() + 1 }}
1362
- }
1363
- @default {
1364
- {{ val }}
1365
- }
1366
- }
1367
- `, imports: [NgTemplateOutlet, DatePipe, DecimalPipe], styles: [":host{width:100%;text-align:inherit}\n"] }]
1368
- }], propDecorators: { index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: true }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }] } });
1369
-
1370
- const COLUMN_STATE_PRIORITY_KEYS = new Set(['disabled', 'visible', 'sticky']);
1371
- function mergeDeclarativeColumns(declarative, columns) {
1372
- if (!declarative.length) {
1373
- return columns;
1374
- }
1375
- if (!columns.length) {
1376
- return declarative;
1377
- }
1378
- const declarativeByKey = new Map(declarative.map((column) => [column.key, column]));
1379
- const usedKeys = new Set();
1380
- const merged = [];
1381
- for (const column of columns) {
1382
- const base = declarativeByKey.get(column.key);
1383
- if (!base) {
1384
- merged.push(column);
1385
- continue;
1386
- }
1387
- usedKeys.add(column.key);
1388
- merged.push(mergeColumnState(base, column));
1389
- }
1390
- for (const column of declarative) {
1391
- if (!usedKeys.has(column.key)) {
1392
- merged.push(column);
1393
- }
1394
- }
1395
- return merged;
1396
- }
1397
- function mergeColumnState(declarative, state) {
1398
- const merged = { ...declarative };
1399
- const stateValue = state;
1400
- for (const key of Object.keys(stateValue)) {
1401
- if (key === 'key') {
1402
- continue;
1403
- }
1404
- const value = stateValue[key];
1405
- if (COLUMN_STATE_PRIORITY_KEYS.has(key)) {
1406
- if (value !== undefined) {
1407
- merged[key] = value;
1408
- }
1409
- continue;
1410
- }
1411
- if (merged[key] === undefined && value !== undefined) {
1412
- merged[key] = value;
1413
- }
1414
- }
1415
- return merged;
1416
- }
1417
-
1418
- // noinspection ES6PreferShortImport
1419
- function normalizeDeclarativeColumns(defs = [], rowKey) {
1420
- const columns = [];
1421
- const rowCellTemplatesByKey = new Map();
1422
- for (const def of defs) {
1423
- const key = def.key;
1424
- const base = {
1425
- key,
1426
- header: def.header ?? String(key),
1427
- headerTemplate: def.headerTemplate,
1428
- align: def.align,
1429
- sortKey: def.sortKey,
1430
- width: def.width,
1431
- minWidth: def.minWidth,
1432
- maxWidth: def.maxWidth,
1433
- flex: def.flex,
1434
- disabled: def.disabled,
1435
- visible: def.visible,
1436
- sticky: def.sticky,
1437
- tooltip: def.tooltip,
1438
- expandBy: def.expandBy,
1439
- };
1440
- if (def.cellTemplate) {
1441
- rowCellTemplatesByKey.set(String(key), def.cellTemplate);
1442
- }
1443
- if (def.value) {
1444
- columns.push({
1445
- ...base,
1446
- value: def.value,
1447
- track: def.track ?? createDefaultTrack(key, rowKey),
1448
- });
1449
- continue;
1450
- }
1451
- columns.push({
1452
- ...base,
1453
- type: def.type ?? 'plain',
1454
- typeParams: def.typeParams,
1455
- defaultValue: def.defaultValue,
1456
- });
1457
- }
1458
- return { columns, rowCellTemplatesByKey };
1459
- }
1460
- function createDefaultTrack(key, rowKey) {
1461
- return (row) => {
1462
- if (!rowKey) {
1463
- return String(row[key]);
1464
- }
1465
- if (typeof rowKey === 'function') {
1466
- return String(rowKey(row));
1467
- }
1468
- return String(row[rowKey]);
1469
- };
1470
- }
1471
-
1472
- /**
1473
- * Service class for managing row selection in a data grid.
1474
- *
1475
- * Handles selection state and operations for grid rows, supporting multiple selection modes
1476
- * (none, single, multi). Provides reactive signals for tracking selected items and
1477
- * computed values for selection state.
1478
- *
1479
- * @template Data - The type of data objects in the grid, must extend `AnyDict`.
1480
- *
1481
- * @example
1482
- * ```typescript
1483
- * const selector = new Selector<User>();
1484
- * selector.data.set(users);
1485
- * selector.selection.set({ mode: 'multi', key: 'id' });
1486
- * selector.select(users[0]);
1487
- * console.log(selector.selectedKeys()); // ['user-id']
1488
- * ```
1489
- */
1490
- class Selector {
1491
- /**
1492
- * Signal containing the full dataset of grid rows.
1493
- *
1494
- * This signal holds all data items that can be selected.
1495
- * Defaults to an empty array.
1496
- */
1497
- data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1498
- /**
1499
- * Signal containing the current selection configuration.
1500
- *
1501
- * Defines the selection mode and the key property used for identifying rows.
1502
- * Defaults to `{ mode: 'none' }` which disables selection.
1503
- */
1504
- selection = signal({ mode: 'none' }, ...(ngDevMode ? [{ debugName: "selection" }] : []));
1505
- /**
1506
- * Signal containing the array of currently selected row keys.
1507
- *
1508
- * Stores the keys of all selected rows based on the key property
1509
- * defined in the selection configuration.
1510
- * Defaults to an empty array.
1511
- */
1512
- selectedKeys = signal([], ...(ngDevMode ? [{ debugName: "selectedKeys" }] : []));
1513
- /**
1514
- * Computed signal indicating the overall selection state of all rows.
1515
- *
1516
- * Returns:
1517
- * - `true` if all rows are selected
1518
- * - `false` if no rows are selected
1519
- * - `'mixed'` if some but not all rows are selected
1520
- *
1521
- * Useful for implementing the "select all" checkbox with an indeterminate state.
1522
- */
1523
- isAllSelected = computed(() => {
1524
- const selectedCount = this.selectedKeys().length;
1525
- return selectedCount === this.data().length ? true : selectedCount === 0 ? false : 'mixed';
1526
- }, ...(ngDevMode ? [{ debugName: "isAllSelected" }] : []));
1527
- /**
1528
- * Checks whether a specific row is currently selected.
1529
- *
1530
- * Compares the row's key value against the list of selected keys.
1531
- * Returns `false` if the selection mode is 'none' or the key is not configured.
1532
- *
1533
- * @param row - The data row to check selection status for.
1534
- * @returns `true` if the row is selected, `false` otherwise.
1535
- */
1536
- isSelected(row) {
1537
- const selection = this.selection();
1538
- const selected = this.selectedKeys();
1539
- return 'key' in selection ? selected.includes(row[selection.key]) : false;
1540
- }
1541
- /**
1542
- * Toggles selection of all rows.
1543
- *
1544
- * If all rows are selected, deselects all.
1545
- * If no rows or some rows are selected, selects all.
1546
- *
1547
- * This method only works in `'multi'` selection mode and throws an error
1548
- * if called in any other mode.
1549
- *
1550
- * @returns The updated array of selected keys.
1551
- * @throws {Error} If selection mode is not `'multi'`.
1552
- */
1553
- selectAll() {
1554
- if (this.selection().mode !== 'multi') {
1555
- throw new Error('Cannot select all in not "multi" mode');
1556
- }
1557
- const selection = this.selection();
1558
- const state = this.isAllSelected();
1559
- const nextState = state === false || state === 'mixed';
1560
- this.selectedKeys.set(!nextState ? [] : this.data().map((row) => row[selection.key]));
1561
- return this.selectedKeys();
1562
- }
1563
- /**
1564
- * Selects or deselects a specific row.
1565
- *
1566
- * Behavior depends on the selection mode:
1567
- * - In `'single'` mode: replaces current selection with the specified row.
1568
- * - In `'multi'` mode: toggles the row's selection state (adds if not selected, removes if selected).
1569
- * - In `'none'` mode: throws an error.
1570
- *
1571
- * @param row - The data row to select or deselect.
1572
- * @returns The updated array of selected keys after the operation.
1573
- * @throws {Error} If selection mode is `'none'`.
1574
- */
1575
- select(row) {
1576
- if (this.selection().mode === 'none') {
1577
- throw new Error('Cannot select row in "none" mode');
1578
- }
1579
- const selection = this.selection();
1580
- if (this.selection().mode === 'single') {
1581
- const selected = [row[selection.key]];
1582
- this.selectedKeys.set(selected);
1583
- return selected;
1584
- }
1585
- else {
1586
- const selectedKeys = this.selectedKeys();
1587
- const has = selectedKeys.some((it) => it === row[selection.key]);
1588
- const selected = has
1589
- ? selectedKeys.filter((it) => it !== row[selection.key])
1590
- : [...selectedKeys, row[selection.key]];
1591
- this.selectedKeys.set(selected);
1592
- return selected;
1593
- }
1594
- }
1595
- }
1596
-
1597
- // noinspection CssUnresolvedCustomProperty
1598
- class CheckboxIcon {
1599
- state = input(false, ...(ngDevMode ? [{ debugName: "state" }] : []));
1600
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1601
- boxRef = viewChild((ElementRef), ...(ngDevMode ? [{ debugName: "boxRef" }] : []));
1602
- constructor() {
1603
- effect(() => {
1604
- const el = this.boxRef()?.nativeElement;
1605
- if (!el) {
1606
- return;
1607
- }
1608
- const state = this.state();
1609
- if (state === 'mixed') {
1610
- el.indeterminate = true;
1611
- el.checked = false;
1612
- el.dataset.indeterminate = 'true';
1613
- }
1614
- else if (state) {
1615
- el.indeterminate = false;
1616
- el.checked = true;
1617
- el.dataset.indeterminate = 'false';
1618
- }
1619
- else {
1620
- el.indeterminate = false;
1621
- el.checked = false;
1622
- el.dataset.indeterminate = 'false';
1623
- }
1624
- });
1625
- }
1626
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CheckboxIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
1627
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.1", type: CheckboxIcon, isStandalone: true, selector: "re-checkbox-ic", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "boxRef", first: true, predicate: (ElementRef), descendants: true, isSignal: true }], ngImport: i0, template: `
1628
- <label class="cb" [class.cb--disabled]="disabled()">
1629
- <input
1630
- #box
1631
- class="cb__input"
1632
- type="checkbox"
1633
- aria-hidden="true"
1634
- [disabled]="disabled()"
1635
- [checked]="state() === true"
1636
- [attr.data-indeterminate]="state() === 'mixed' ? 'true' : 'false'"
1637
- (click)="$event.stopPropagation()"
1638
- />
1639
- <span class="cb__box" aria-hidden="true"></span>
1640
- </label>
1641
- `, isInline: true, styles: [":host{--re-data-grid-checkbox-size: 20px;--re-data-grid-checkbox-stroke: 2px;--re-data-grid-checkbox-border: var(--border-color, #9aa3af);--re-data-grid-checkbox-tick: var(--surface-neutral, #fff);--re-data-grid-checkbox-surface: var(--surface-neutral, #fff);--re-data-grid-checkbox-active-color: var(--primary-color, #2563eb);display:inline-block;width:var(--re-data-grid-checkbox-size);height:var(--re-data-grid-checkbox-size);-webkit-user-select:none;user-select:none}.cb{cursor:default;display:inline-block}.cb--disabled{opacity:.6}.cb__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.cb__box{position:relative;display:inline-block;width:var(--re-data-grid-checkbox-size);height:var(--re-data-grid-checkbox-size);border:var(--re-data-grid-checkbox-stroke) solid var(--re-data-grid-checkbox-border);border-radius:4px;background:var(--re-data-grid-checkbox-surface);transition:background .25s,border-color .25s}.cb__input:checked+.cb__box{border-color:var(--re-data-grid-checkbox-active-color);background:var(--re-data-grid-checkbox-active-color)}.cb__input:checked+.cb__box:after{content:\"\";position:absolute;inset:0;margin:auto;width:10px;height:6px;border:2px solid var(--re-data-grid-checkbox-tick);border-top:0;border-right:0;transform:rotate(-45deg) translate(1px,-1px) scale(.8);opacity:0;animation:tick .25s forwards ease}.cb__input[data-indeterminate=true]+.cb__box{background:var(--re-data-grid-checkbox-active-color);border-color:var(--re-data-grid-checkbox-active-color)}.cb__input[data-indeterminate=true]+.cb__box:after{content:\"\";position:absolute;left:3px;right:3px;top:50%;border-top:2px solid var(--re-data-grid-checkbox-tick);transform:translateY(-50%) scaleX(.3);opacity:0;animation:dash .25s forwards ease}@keyframes tick{to{opacity:1;transform:rotate(-45deg) translate(1px,-1px) scale(1)}}@keyframes dash{to{opacity:1;transform:translateY(-50%) scaleX(1)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1642
- }
1643
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CheckboxIcon, decorators: [{
1644
- type: Component,
1645
- args: [{ selector: 're-checkbox-ic', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1646
- <label class="cb" [class.cb--disabled]="disabled()">
1647
- <input
1648
- #box
1649
- class="cb__input"
1650
- type="checkbox"
1651
- aria-hidden="true"
1652
- [disabled]="disabled()"
1653
- [checked]="state() === true"
1654
- [attr.data-indeterminate]="state() === 'mixed' ? 'true' : 'false'"
1655
- (click)="$event.stopPropagation()"
1656
- />
1657
- <span class="cb__box" aria-hidden="true"></span>
1658
- </label>
1659
- `, styles: [":host{--re-data-grid-checkbox-size: 20px;--re-data-grid-checkbox-stroke: 2px;--re-data-grid-checkbox-border: var(--border-color, #9aa3af);--re-data-grid-checkbox-tick: var(--surface-neutral, #fff);--re-data-grid-checkbox-surface: var(--surface-neutral, #fff);--re-data-grid-checkbox-active-color: var(--primary-color, #2563eb);display:inline-block;width:var(--re-data-grid-checkbox-size);height:var(--re-data-grid-checkbox-size);-webkit-user-select:none;user-select:none}.cb{cursor:default;display:inline-block}.cb--disabled{opacity:.6}.cb__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.cb__box{position:relative;display:inline-block;width:var(--re-data-grid-checkbox-size);height:var(--re-data-grid-checkbox-size);border:var(--re-data-grid-checkbox-stroke) solid var(--re-data-grid-checkbox-border);border-radius:4px;background:var(--re-data-grid-checkbox-surface);transition:background .25s,border-color .25s}.cb__input:checked+.cb__box{border-color:var(--re-data-grid-checkbox-active-color);background:var(--re-data-grid-checkbox-active-color)}.cb__input:checked+.cb__box:after{content:\"\";position:absolute;inset:0;margin:auto;width:10px;height:6px;border:2px solid var(--re-data-grid-checkbox-tick);border-top:0;border-right:0;transform:rotate(-45deg) translate(1px,-1px) scale(.8);opacity:0;animation:tick .25s forwards ease}.cb__input[data-indeterminate=true]+.cb__box{background:var(--re-data-grid-checkbox-active-color);border-color:var(--re-data-grid-checkbox-active-color)}.cb__input[data-indeterminate=true]+.cb__box:after{content:\"\";position:absolute;left:3px;right:3px;top:50%;border-top:2px solid var(--re-data-grid-checkbox-tick);transform:translateY(-50%) scaleX(.3);opacity:0;animation:dash .25s forwards ease}@keyframes tick{to{opacity:1;transform:rotate(-45deg) translate(1px,-1px) scale(1)}}@keyframes dash{to{opacity:1;transform:translateY(-50%) scaleX(1)}}\n"] }]
1660
- }], ctorParameters: () => [], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], boxRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ElementRef), { isSignal: true }] }] } });
1661
-
1662
- /* eslint-disable max-len */
1663
- class ExpandIcon {
1664
- expanded = input(false, { ...(ngDevMode ? { debugName: "expanded" } : {}), transform: booleanAttribute });
1665
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ExpandIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
1666
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: ExpandIcon, isStandalone: true, selector: "re-expand-ic", inputs: { expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1667
- @if (expanded()) {
1668
- <svg width="16" height="16" viewBox="0 0 16 16">
1669
- <path
1670
- d="M15.5 8C15.5 9.48336 15.0601 10.9334 14.236 12.1668C13.4119 13.4001 12.2406 14.3614 10.8701 14.9291C9.49968 15.4968 7.99168 15.6453 6.53683 15.3559C5.08197 15.0665 3.7456 14.3522 2.6967 13.3033C1.64781 12.2544 0.933503 10.918 0.644114 9.46318C0.354725 8.00832 0.50325 6.50032 1.07091 5.12987C1.63856 3.75943 2.59986 2.58809 3.83323 1.76398C5.0666 0.939867 6.51664 0.5 8 0.5C8.98492 0.5 9.96019 0.693993 10.8701 1.0709C11.7801 1.44781 12.6069 2.00026 13.3033 2.6967C13.9997 3.39314 14.5522 4.21993 14.9291 5.12987C15.306 6.03982 15.5 7.01509 15.5 8ZM12.5 8C12.5 7.80109 12.421 7.61032 12.2803 7.46967C12.1397 7.32902 11.9489 7.25 11.75 7.25H4.25C4.05109 7.25 3.86033 7.32902 3.71967 7.46967C3.57902 7.61032 3.5 7.80109 3.5 8C3.5 8.19891 3.57902 8.38968 3.71967 8.53033C3.86033 8.67098 4.05109 8.75 4.25 8.75H11.75C11.9489 8.75 12.1397 8.67098 12.2803 8.53033C12.421 8.38968 12.5 8.19891 12.5 8Z"
1671
- fill="var(--re-data-grid-expander-color)"
1672
- />
1673
- </svg>
1674
- } @else {
1675
- <svg width="16" height="16" viewBox="0 0 16 16">
1676
- <path
1677
- d="M8 0.5C6.51664 0.5 5.0666 0.939867 3.83323 1.76398C2.59986 2.58809 1.63856 3.75943 1.07091 5.12987C0.50325 6.50032 0.354725 8.00832 0.644114 9.46318C0.933503 10.918 1.64781 12.2544 2.6967 13.3033C3.7456 14.3522 5.08197 15.0665 6.53683 15.3559C7.99168 15.6453 9.49968 15.4968 10.8701 14.9291C12.2406 14.3614 13.4119 13.4001 14.236 12.1668C15.0601 10.9334 15.5 9.48336 15.5 8C15.5 7.01509 15.306 6.03982 14.9291 5.12987C14.5522 4.21993 13.9997 3.39314 13.3033 2.6967C12.6069 2.00026 11.7801 1.44781 10.8701 1.0709C9.96019 0.693993 8.98492 0.5 8 0.5ZM11.75 8.75H8.75V11.75C8.75 11.9489 8.67099 12.1397 8.53033 12.2803C8.38968 12.421 8.19892 12.5 8 12.5C7.80109 12.5 7.61033 12.421 7.46967 12.2803C7.32902 12.1397 7.25 11.9489 7.25 11.75V8.75H4.25C4.05109 8.75 3.86033 8.67098 3.71967 8.53033C3.57902 8.38968 3.5 8.19891 3.5 8C3.5 7.80109 3.57902 7.61032 3.71967 7.46967C3.86033 7.32902 4.05109 7.25 4.25 7.25H7.25V4.25C7.25 4.05109 7.32902 3.86032 7.46967 3.71967C7.61033 3.57902 7.80109 3.5 8 3.5C8.19892 3.5 8.38968 3.57902 8.53033 3.71967C8.67099 3.86032 8.75 4.05109 8.75 4.25V7.25H11.75C11.9489 7.25 12.1397 7.32902 12.2803 7.46967C12.421 7.61032 12.5 7.80109 12.5 8C12.5 8.19891 12.421 8.38968 12.2803 8.53033C12.1397 8.67098 11.9489 8.75 11.75 8.75Z"
1678
- fill="var(--re-data-grid-expander-color)"
1679
- />
1680
- </svg>
1681
- }
1682
- `, isInline: true, styles: [""] });
1683
- }
1684
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ExpandIcon, decorators: [{
1685
- type: Component,
1686
- args: [{ selector: 're-expand-ic', template: `
1687
- @if (expanded()) {
1688
- <svg width="16" height="16" viewBox="0 0 16 16">
1689
- <path
1690
- d="M15.5 8C15.5 9.48336 15.0601 10.9334 14.236 12.1668C13.4119 13.4001 12.2406 14.3614 10.8701 14.9291C9.49968 15.4968 7.99168 15.6453 6.53683 15.3559C5.08197 15.0665 3.7456 14.3522 2.6967 13.3033C1.64781 12.2544 0.933503 10.918 0.644114 9.46318C0.354725 8.00832 0.50325 6.50032 1.07091 5.12987C1.63856 3.75943 2.59986 2.58809 3.83323 1.76398C5.0666 0.939867 6.51664 0.5 8 0.5C8.98492 0.5 9.96019 0.693993 10.8701 1.0709C11.7801 1.44781 12.6069 2.00026 13.3033 2.6967C13.9997 3.39314 14.5522 4.21993 14.9291 5.12987C15.306 6.03982 15.5 7.01509 15.5 8ZM12.5 8C12.5 7.80109 12.421 7.61032 12.2803 7.46967C12.1397 7.32902 11.9489 7.25 11.75 7.25H4.25C4.05109 7.25 3.86033 7.32902 3.71967 7.46967C3.57902 7.61032 3.5 7.80109 3.5 8C3.5 8.19891 3.57902 8.38968 3.71967 8.53033C3.86033 8.67098 4.05109 8.75 4.25 8.75H11.75C11.9489 8.75 12.1397 8.67098 12.2803 8.53033C12.421 8.38968 12.5 8.19891 12.5 8Z"
1691
- fill="var(--re-data-grid-expander-color)"
1692
- />
1693
- </svg>
1694
- } @else {
1695
- <svg width="16" height="16" viewBox="0 0 16 16">
1696
- <path
1697
- d="M8 0.5C6.51664 0.5 5.0666 0.939867 3.83323 1.76398C2.59986 2.58809 1.63856 3.75943 1.07091 5.12987C0.50325 6.50032 0.354725 8.00832 0.644114 9.46318C0.933503 10.918 1.64781 12.2544 2.6967 13.3033C3.7456 14.3522 5.08197 15.0665 6.53683 15.3559C7.99168 15.6453 9.49968 15.4968 10.8701 14.9291C12.2406 14.3614 13.4119 13.4001 14.236 12.1668C15.0601 10.9334 15.5 9.48336 15.5 8C15.5 7.01509 15.306 6.03982 14.9291 5.12987C14.5522 4.21993 13.9997 3.39314 13.3033 2.6967C12.6069 2.00026 11.7801 1.44781 10.8701 1.0709C9.96019 0.693993 8.98492 0.5 8 0.5ZM11.75 8.75H8.75V11.75C8.75 11.9489 8.67099 12.1397 8.53033 12.2803C8.38968 12.421 8.19892 12.5 8 12.5C7.80109 12.5 7.61033 12.421 7.46967 12.2803C7.32902 12.1397 7.25 11.9489 7.25 11.75V8.75H4.25C4.05109 8.75 3.86033 8.67098 3.71967 8.53033C3.57902 8.38968 3.5 8.19891 3.5 8C3.5 7.80109 3.57902 7.61032 3.71967 7.46967C3.86033 7.32902 4.05109 7.25 4.25 7.25H7.25V4.25C7.25 4.05109 7.32902 3.86032 7.46967 3.71967C7.61033 3.57902 7.80109 3.5 8 3.5C8.19892 3.5 8.38968 3.57902 8.53033 3.71967C8.67099 3.86032 8.75 4.05109 8.75 4.25V7.25H11.75C11.9489 7.25 12.1397 7.32902 12.2803 7.46967C12.421 7.61032 12.5 7.80109 12.5 8C12.5 8.19891 12.421 8.38968 12.2803 8.53033C12.1397 8.67098 11.9489 8.75 11.75 8.75Z"
1698
- fill="var(--re-data-grid-expander-color)"
1699
- />
1700
- </svg>
1701
- }
1702
- ` }]
1703
- }], propDecorators: { expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }] } });
1704
-
1705
- /* eslint-disable max-len */
1706
- class SortIcon {
1707
- direction = input('asc', ...(ngDevMode ? [{ debugName: "direction" }] : []));
1708
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SortIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
1709
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.1", type: SortIcon, isStandalone: true, selector: "re-sort-ic", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1710
- <svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
1711
- <path
1712
- d="M12.84 8.51259L9.66754 11.6851V4.59009C9.66754 4.39118 9.58852 4.20041 9.44787 4.05976C9.30722 3.91911 9.11645 3.84009 8.91754 3.84009C8.71863 3.84009 8.52786 3.91911 8.38721 4.05976C8.24656 4.20041 8.16754 4.39118 8.16754 4.59009V11.6851L4.99504 8.51259C4.92511 8.44266 4.84209 8.38719 4.75073 8.34934C4.65936 8.3115 4.56144 8.29202 4.46254 8.29202C4.36365 8.29202 4.26572 8.3115 4.17435 8.34934C4.08299 8.38719 3.99997 8.44266 3.93004 8.51259C3.86011 8.58252 3.80464 8.66553 3.7668 8.7569C3.72895 8.84827 3.70947 8.94619 3.70947 9.04509C3.70947 9.14398 3.72895 9.24191 3.7668 9.33327C3.80464 9.42464 3.86011 9.50766 3.93004 9.57759L8.38504 14.0251C8.45349 14.0952 8.53503 14.1513 8.62504 14.1901C8.71842 14.2256 8.81762 14.2435 8.91754 14.2426C9.01505 14.2438 9.11186 14.226 9.20254 14.1901C9.29255 14.1513 9.37409 14.0952 9.44254 14.0251L13.8975 9.57759C13.9678 9.50787 14.0236 9.42491 14.0617 9.33352C14.0998 9.24213 14.1194 9.1441 14.1194 9.04509C14.1194 8.94608 14.0998 8.84805 14.0617 8.75666C14.0236 8.66526 13.9678 8.58231 13.8975 8.51259C13.757 8.3729 13.5669 8.29449 13.3688 8.29449C13.1707 8.29449 12.9806 8.3729 12.84 8.51259Z"
1713
- fill="currentColor"
1714
- />
1715
- </svg>
1716
- `, isInline: true, styles: ["svg{transition:transform .3s ease-in-out}svg:not(.asc):not(.desc){display:none}.asc{transform:rotate(-180deg)}.desc{transform:rotate(0)}\n"] });
1717
- }
1718
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SortIcon, decorators: [{
1719
- type: Component,
1720
- args: [{ selector: 're-sort-ic', template: `
1721
- <svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
1722
- <path
1723
- d="M12.84 8.51259L9.66754 11.6851V4.59009C9.66754 4.39118 9.58852 4.20041 9.44787 4.05976C9.30722 3.91911 9.11645 3.84009 8.91754 3.84009C8.71863 3.84009 8.52786 3.91911 8.38721 4.05976C8.24656 4.20041 8.16754 4.39118 8.16754 4.59009V11.6851L4.99504 8.51259C4.92511 8.44266 4.84209 8.38719 4.75073 8.34934C4.65936 8.3115 4.56144 8.29202 4.46254 8.29202C4.36365 8.29202 4.26572 8.3115 4.17435 8.34934C4.08299 8.38719 3.99997 8.44266 3.93004 8.51259C3.86011 8.58252 3.80464 8.66553 3.7668 8.7569C3.72895 8.84827 3.70947 8.94619 3.70947 9.04509C3.70947 9.14398 3.72895 9.24191 3.7668 9.33327C3.80464 9.42464 3.86011 9.50766 3.93004 9.57759L8.38504 14.0251C8.45349 14.0952 8.53503 14.1513 8.62504 14.1901C8.71842 14.2256 8.81762 14.2435 8.91754 14.2426C9.01505 14.2438 9.11186 14.226 9.20254 14.1901C9.29255 14.1513 9.37409 14.0952 9.44254 14.0251L13.8975 9.57759C13.9678 9.50787 14.0236 9.42491 14.0617 9.33352C14.0998 9.24213 14.1194 9.1441 14.1194 9.04509C14.1194 8.94608 14.0998 8.84805 14.0617 8.75666C14.0236 8.66526 13.9678 8.58231 13.8975 8.51259C13.757 8.3729 13.5669 8.29449 13.3688 8.29449C13.1707 8.29449 12.9806 8.3729 12.84 8.51259Z"
1724
- fill="currentColor"
1725
- />
1726
- </svg>
1727
- `, styles: ["svg{transition:transform .3s ease-in-out}svg:not(.asc):not(.desc){display:none}.asc{transform:rotate(-180deg)}.desc{transform:rotate(0)}\n"] }]
1728
- }], propDecorators: { direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }] } });
1729
-
1730
- /**
1731
- * Data grid component with virtual scrolling, sorting, selection, and pagination support.
1732
- *
1733
- * Provides high-performance rendering of large datasets with features like:
1734
- * - Virtual scrolling for efficient DOM management
1735
- * - Column sorting and expandable columns
1736
- * - Row selection (single/multiple)
1737
- * - Pagination modes: none, pagination, or infinite scroll
1738
- * - Pinned rows
1739
- * - Custom cell and header templates
1740
- *
1741
- * @example
1742
- * ```html
1743
- * <re-data-grid
1744
- * [data]="users"
1745
- * [columns]="columns"
1746
- * [selection]="{ mode: 'multiple' }"
1747
- * (sortChange)="onSort($event)"
1748
- * />
1749
- * ```
1750
- */
1751
- class DataGrid {
1752
- defaults = inject(DATA_GRID_CONFIG) || DEFAULT_DATA_GRID_DEFAULTS;
1753
- /**
1754
- * Array of data to display in the table.
1755
- *
1756
- * Each item represents a single row. The component will efficiently render
1757
- * only visible rows using virtual scrolling.
1758
- */
1759
- data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1760
- /**
1761
- * Column configuration for the table.
1762
- *
1763
- * Defines how each column should be rendered, sorted, and styled.
1764
- * Supports custom templates, sorting keys, and expandable columns.
1765
- */
1766
- columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
1767
- /**
1768
- * Pagination mode: 'none', 'pagination', or 'infinity'.
1769
- *
1770
- * - `none` - No pagination, all data is rendered
1771
- * - `pagination` - Classic page-based pagination with fixed page size
1772
- * - `infinity` - Infinite scroll mode, loads more data as user scrolls
1773
- */
1774
- mode = input(this.defaults.mode, ...(ngDevMode ? [{ debugName: "mode" }] : []));
1775
- /**
1776
- * Array of pinned rows that remain visible at the top or bottom.
1777
- *
1778
- * Pinned rows stay fixed while the rest of the content scrolls.
1779
- * Useful for totals, summaries, or always-visible items.
1780
- */
1781
- pinnedRows = input([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
1782
- /**
1783
- * Function to determine if a row should become sticky at the top.
1784
- *
1785
- * When provided, rows matching this predicate will stick to the top
1786
- * of the scroll area as the user scrolls.
1787
- */
1788
- isRowSticky = input(undefined, ...(ngDevMode ? [{ debugName: "isRowSticky" }] : []));
1789
- /**
1790
- * Function to choose a custom template for a row.
1791
- *
1792
- * If it returns a template, the row will be rendered with it;
1793
- * otherwise, the default row rendering is used.
1794
- */
1795
- getRowTemplate = input(undefined, ...(ngDevMode ? [{ debugName: "getRowTemplate" }] : []));
1796
- /**
1797
- * Whether to add an index column showing row numbers.
1798
- *
1799
- * When enabled, it automatically adds a column displaying sequential row numbers.
1800
- */
1801
- hasIndexColumn = input(this.defaults.hasIndexColumn, { ...(ngDevMode ? { debugName: "hasIndexColumn" } : {}), transform: booleanAttribute });
1802
- /**
1803
- * Row selection configuration.
1804
- *
1805
- * Controls whether users can select rows and in what mode:
1806
- * - `{ mode: 'none' }` - No selection
1807
- * - `{ mode: 'single' }` - Single row selection
1808
- * - `{ mode: 'multi' }` - Multiple row selection with checkboxes
1809
- *
1810
- * When selection is enabled, a `key` must be provided to identify rows.
1811
- */
1812
- selection = input(this.defaults.selection, ...(ngDevMode ? [{ debugName: "selection" }] : []));
1813
- /**
1814
- * Number of items per page.
1815
- *
1816
- * Used in pagination and infinity scroll modes to control
1817
- * how many rows are loaded at once. Default is 20.
1818
- */
1819
- pageSize = input(this.defaults.pageSize, { ...(ngDevMode ? { debugName: "pageSize" } : {}), transform: numberAttribute });
1820
- /**
1821
- * Height of each row in pixels.
1822
- *
1823
- * Used for virtual scrolling calculations. Must be consistent
1824
- * across all rows for accurate scrolling. Default is 40.
1825
- */
1826
- rowHeight = input(this.defaults.rowHeight, { ...(ngDevMode ? { debugName: "rowHeight" } : {}), transform: numberAttribute });
1827
- /**
1828
- * Grid height configuration.
1829
- *
1830
- * - `number` - Fixed height in pixels
1831
- * - `'full'` - Fill container height (100%), can be managed by host component style
1832
- * - `'default'` - Height by CSS var (--re-data-grid-height)
1833
- */
1834
- height = input(this.defaults.height, ...(ngDevMode ? [{ debugName: "height" }] : []));
1835
- /**
1836
- * Size of the virtual scroll buffer.
1837
- *
1838
- * Number of extra rows to render above and below the viewport
1839
- * to reduce flickering during fast scrolling. Default is 8.
1840
- */
1841
- virtualBuffer = input(this.defaults.virtualBuffer, ...(ngDevMode ? [{ debugName: "virtualBuffer" }] : []));
1842
- /**
1843
- * Locks vertical scrolling while keeping horizontal scrolling enabled.
1844
- *
1845
- * Useful when the grid height is fixed by the parent and vertical scrolling
1846
- * should be managed externally.
1847
- */
1848
- lockVerticalScroll = input(false, { ...(ngDevMode ? { debugName: "lockVerticalScroll" } : {}), transform: booleanAttribute });
1849
- /**
1850
- * Header group configuration for creating multi-level column headers.
1851
- *
1852
- * Allows grouping multiple columns under a common header label.
1853
- * Each group spans from a starting column to an ending column and can have a custom alignment.
1854
- *
1855
- * @example
1856
- * ```typescript
1857
- * headerGroups = [
1858
- * {
1859
- * key: 'personal-info',
1860
- * title: 'Personal Information',
1861
- * from: 'name',
1862
- * to: 'email',
1863
- * align: 'center'
1864
- * }
1865
- * ];
1866
- * ```
1867
- */
1868
- headerGroups = input([], ...(ngDevMode ? [{ debugName: "headerGroups" }] : []));
1869
- /**
1870
- * Loading state indicator.
1871
- *
1872
- * When true, displays loading template instead of data.
1873
- * Useful during async data fetching operations.
1874
- */
1875
- loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : {}), transform: booleanAttribute });
1876
- loadingMode = input(this.defaults.loadingMode, ...(ngDevMode ? [{ debugName: "loadingMode" }] : []));
1877
- deferContent = input(this.defaults.deferContent, { ...(ngDevMode ? { debugName: "deferContent" } : {}), transform: booleanAttribute });
1878
- deferHeader = input(this.defaults.deferHeader, { ...(ngDevMode ? { debugName: "deferHeader" } : {}), transform: booleanAttribute });
1879
- deferPinned = input(this.defaults.deferPinned, { ...(ngDevMode ? { debugName: "deferPinned" } : {}), transform: booleanAttribute });
1880
- deferCells = input(this.defaults.deferCells, { ...(ngDevMode ? { debugName: "deferCells" } : {}), transform: booleanAttribute });
1881
- deferIcons = input(this.defaults.deferIcons, { ...(ngDevMode ? { debugName: "deferIcons" } : {}), transform: booleanAttribute });
1882
- deferTooltip = input(this.defaults.deferTooltip, { ...(ngDevMode ? { debugName: "deferTooltip" } : {}), transform: booleanAttribute });
1883
- /**
1884
- * Function or property name for getting a unique row key.
1885
- *
1886
- * Used for efficient change detection and row tracking.
1887
- * Can be a property name (string) or a function that returns a unique identifier.
1888
- */
1889
- rowKey = input(undefined, ...(ngDevMode ? [{ debugName: "rowKey" }] : []));
1890
- /**
1891
- * Whether to start a page count from 0 (true) or 1 (false).
1892
- *
1893
- * Controls the numbering scheme for pagination events.
1894
- * Default is true (0-based indexing).
1895
- */
1896
- pageStartFromZero = input(this.defaults.pageStartFromZero, { ...(ngDevMode ? { debugName: "pageStartFromZero" } : {}), transform: booleanAttribute });
1897
- /**
1898
- * Event emitted when requesting data for a new page.
1899
- *
1900
- * Fired in pagination and infinity scroll modes when the user navigates
1901
- * to a different page or scrolls near the end of current data.
1902
- *
1903
- * @example
1904
- * ```typescript
1905
- * onPageChange(event: GridPageChangeEvent) {
1906
- * this.loadData(event.page, event.rows);
1907
- * }
1908
- * ```
1909
- */
1910
- pageChange = output();
1911
- /**
1912
- * Event emitted when sort order changes.
1913
- *
1914
- * Fired when a user clicks on a sortable column header.
1915
- * Contains the sort key and direction (asc/desc).
1916
- *
1917
- * @example
1918
- * ```typescript
1919
- * onSortChange(event: GridSortEvent<User>) {
1920
- * this.data = sortBy(this.data, event.key, event.order);
1921
- * }
1922
- * ```
1923
- */
1924
- sortChange = output();
1925
- /**
1926
- * Event emitted when selected rows change.
1927
- *
1928
- * Fired when a user selects or deselects rows.
1929
- * Contains an array of currently selected row keys.
1930
- */
1931
- selectChange = output();
1932
- /**
1933
- * Event emitted when a row is clicked.
1934
- *
1935
- * Contains the clicked row data and its index.
1936
- */
1937
- rowClick = output();
1938
- /**
1939
- * Event emitted when a row is right-clicked (context menu).
1940
- *
1941
- * Contains the clicked row data, its index, and the native mouse event.
1942
- */
1943
- rowContext = output();
1944
- /**
1945
- * Event emitted when a row is double-clicked.
1946
- *
1947
- * Contains the clicked row data, its index, and the native mouse event.
1948
- */
1949
- rowDoubleClick = output();
1950
- /**
1951
- * Event emitted when a cell is clicked.
1952
- *
1953
- * Contains the clicked row, column configuration, and row index.
1954
- */
1955
- cellClick = output();
1956
- /**
1957
- * Event emitted when a cell is right-clicked (context menu).
1958
- *
1959
- * Contains the clicked row, column configuration, row index, and the native mouse event.
1960
- */
1961
- cellContext = output();
1962
- /**
1963
- * Event emitted when a cell is double-clicked.
1964
- *
1965
- * Contains the clicked row, column configuration, row index, and the native mouse event.
1966
- */
1967
- cellDoubleClick = output();
1968
- vm = inject((DataGridVm));
1969
- selector = new Selector();
1970
- rootEl = viewChild('root', ...(ngDevMode ? [{ debugName: "rootEl" }] : []));
1971
- scrollEl = viewChild('scroll', ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
1972
- headerEl = viewChild('header', ...(ngDevMode ? [{ debugName: "headerEl" }] : []));
1973
- ngZone = inject(NgZone);
1974
- cellTypedSlotRefs = contentChildren(DataGridTypeCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellTypedSlotRefs" }] : []));
1975
- cellDataSlotRefs = contentChildren(DataGridCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellDataSlotRefs" }] : []));
1976
- declarativeColumnRefs = contentChildren(DataGridDeclarativeColumn, ...(ngDevMode ? [{ debugName: "declarativeColumnRefs" }] : []));
1977
- headerSlotRefs = contentChildren(DataGridHeaderTemplateDirective, ...(ngDevMode ? [{ debugName: "headerSlotRefs" }] : []));
1978
- emptySlotRefs = contentChildren(DataGridCellEmptyDirective, ...(ngDevMode ? [{ debugName: "emptySlotRefs" }] : []));
1979
- loadingSlotRefs = contentChildren(DataGridCellLoadingDirective, ...(ngDevMode ? [{ debugName: "loadingSlotRefs" }] : []));
1980
- sortIcSlotRefs = contentChildren(DataGridSortIconDirective, ...(ngDevMode ? [{ debugName: "sortIcSlotRefs" }] : []));
1981
- expanderIcSlotRefs = contentChildren(DataGridExpanderIconDirective, ...(ngDevMode ? [{ debugName: "expanderIcSlotRefs" }] : []));
1982
- stickyRowSlotRefs = contentChildren(DataGridStickyRowDirective, ...(ngDevMode ? [{ debugName: "stickyRowSlotRefs" }] : []));
1983
- rowSlotRefs = contentChildren(DataGridRowDirective, ...(ngDevMode ? [{ debugName: "rowSlotRefs" }] : []));
1984
- emptyTpl = computed(() => this.emptySlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "emptyTpl" }] : []));
1985
- loadingTpl = computed(() => this.loadingSlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "loadingTpl" }] : []));
1986
- sortTpl = computed(() => this.sortIcSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "sortTpl" }] : []));
1987
- expanderTpl = computed(() => this.expanderIcSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "expanderTpl" }] : []));
1988
- stickyRowTpl = computed(() => this.stickyRowSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "stickyRowTpl" }] : []));
1989
- rowTpl = computed(() => this.rowSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "rowTpl" }] : []));
1990
- renderSlots = signal([], ...(ngDevMode ? [{ debugName: "renderSlots" }] : []));
1991
- renderCount = 0;
1992
- lastStartIndex = -1;
1993
- lastEndIndex = -1;
1994
- startIndex = 0;
1995
- headerHeight = signal(this.defaults.headerHeight, ...(ngDevMode ? [{ debugName: "headerHeight" }] : []));
1996
- tooltipEl = viewChild('tooltip', ...(ngDevMode ? [{ debugName: "tooltipEl" }] : []));
1997
- tooltipState = signal({
1998
- text: '',
1999
- x: 0,
2000
- y: 0,
2001
- visible: false,
2002
- }, ...(ngDevMode ? [{ debugName: "tooltipState" }] : []));
2003
- stickyRowIndex = signal(null, ...(ngDevMode ? [{ debugName: "stickyRowIndex" }] : []));
2004
- stickyRowTopPx = signal(0, ...(ngDevMode ? [{ debugName: "stickyRowTopPx" }] : []));
2005
- stickyRowData = computed(() => {
2006
- const index = this.stickyRowIndex();
2007
- const rows = this.data();
2008
- if (index === null || index < 0 || index >= rows.length) {
2009
- return null;
2010
- }
2011
- return rows[index];
2012
- }, ...(ngDevMode ? [{ debugName: "stickyRowData" }] : []));
2013
- stickyIndexes = signal([], ...(ngDevMode ? [{ debugName: "stickyIndexes" }] : []));
2014
- expanderMap = signal(new Map(), ...(ngDevMode ? [{ debugName: "expanderMap" }] : []));
2015
- declarativeColumns = computed(() => normalizeDeclarativeColumns(this.declarativeColumnRefs().map((columnRef) => columnRef.toDeclarativeColumn()), this.rowKey()), ...(ngDevMode ? [{ debugName: "declarativeColumns" }] : []));
2016
- sourceColumns = computed(() => mergeDeclarativeColumns(this.declarativeColumns().columns, this.columns()), ...(ngDevMode ? [{ debugName: "sourceColumns" }] : []));
2017
- extendedColumns = computed(() => {
2018
- const hasSelection = this.selection().mode !== 'none';
2019
- const hasIndex = this.hasIndexColumn();
2020
- const newColumns = [];
2021
- hasSelection && newColumns.push(GRID_CHECKBOX_COLUMN);
2022
- hasIndex && newColumns.push(GRID_INDEX_COLUMN);
2023
- return [...newColumns, ...this.sourceColumns()];
2024
- }, ...(ngDevMode ? [{ debugName: "extendedColumns" }] : []));
2025
- /**
2026
- * Computed CSS height value based on height setting.
2027
- */
2028
- styleHeight = computed(() => {
2029
- const height = this.height();
2030
- if (typeof height === 'number') {
2031
- return `${height}px`;
2032
- }
2033
- else if (height === 'full') {
2034
- return '100%';
2035
- }
2036
- return 'var(--re-data-grid-height)';
2037
- }, ...(ngDevMode ? [{ debugName: "styleHeight" }] : []));
2038
- hideSbTimeout;
2039
- scrollRafId = null;
2040
- scrollbarRafId = null;
2041
- stickyRafId = null;
2042
- lastInfinityPageRequested = null;
2043
- lastInfinityTotal = -1;
2044
- currentSortField;
2045
- currentSortOrder = 'asc';
2046
- subscription = new Subscription();
2047
- observer;
2048
- resizeSubject = new Subject();
2049
- lastResizeWidth = -1;
2050
- lastResizeHeight = -1;
2051
- constructor() {
2052
- afterRenderEffect(() => {
2053
- this.initRefs();
2054
- this.initHeader();
2055
- this.initScroll();
2056
- this.initObserver();
2057
- });
2058
- afterRenderEffect(() => this.initSelector());
2059
- afterRenderEffect(() => {
2060
- this.initVm();
2061
- this.initSort();
2062
- this.initExpander();
2063
- });
2064
- effect(() => {
2065
- this.data();
2066
- this.rowHeight();
2067
- this.pinnedRows();
2068
- this.isRowSticky();
2069
- this.getRowTemplate();
2070
- this.loading();
2071
- this.mode();
2072
- this.vm.containerWidth();
2073
- this.onVerticalScroll(true);
2074
- });
2075
- effect(() => {
2076
- const total = this.data()?.length ?? 0;
2077
- if (total !== this.lastInfinityTotal) {
2078
- this.lastInfinityTotal = total;
2079
- this.lastInfinityPageRequested = null;
2080
- }
2081
- });
2082
- effect(() => {
2083
- const selection = this.selection();
2084
- if ('defaultSelected' in selection) {
2085
- this.selector.selectedKeys.set(selection.defaultSelected || []);
2086
- }
2087
- });
2088
- effect(() => {
2089
- const selection = this.selection();
2090
- if (selection.mode === 'none' || !('key' in selection)) {
2091
- return;
2092
- }
2093
- const data = this.data() ?? [];
2094
- const key = selection.key;
2095
- const keySet = new Set(data.map((row) => row[key]));
2096
- this.selector.selectedKeys.update((prev) => prev.filter((k) => keySet.has(k)));
2097
- });
2098
- effect(() => {
2099
- const data = this.data() ?? [];
2100
- const predicate = this.isRowSticky();
2101
- if (!predicate || !data.length) {
2102
- this.stickyIndexes.set([]);
2103
- this.updateStickyFromScroll();
2104
- return;
2105
- }
2106
- const indexes = [];
2107
- for (let i = 0; i < data.length; i++) {
2108
- if (predicate(data[i], i)) {
2109
- indexes.push(i);
2110
- }
2111
- }
2112
- this.stickyIndexes.set(indexes);
2113
- this.updateStickyFromScroll();
2114
- });
2115
- inject(DestroyRef).onDestroy(() => {
2116
- this.subscription.unsubscribe();
2117
- this.observer?.disconnect();
2118
- clearTimeout(this.hideSbTimeout);
2119
- this.clearScrollRaf();
2120
- this.clearScrollbarRaf();
2121
- this.clearStickyRaf();
2122
- });
2123
- }
2124
- resolvePinnedData(pr) {
2125
- return typeof pr.data === 'function' ? pr.data() : pr.data;
2126
- }
2127
- /**
2128
- * Handles column header click for sorting.
2129
- *
2130
- * Toggles sort order between ascending and descending for the clicked column.
2131
- * If a different column is clicked, it resets to ascending order.
2132
- * Emits sortChange event with the current sort state.
2133
- *
2134
- * @param col - Column configuration that was clicked
2135
- */
2136
- onSort(col) {
2137
- if (!col.sortKey) {
2138
- return;
2139
- }
2140
- if (this.currentSortField === col.sortKey) {
2141
- this.currentSortOrder = this.currentSortOrder === 'asc' ? 'desc' : 'asc';
2142
- }
2143
- else {
2144
- this.currentSortField = col.sortKey;
2145
- this.currentSortOrder = 'asc';
2146
- }
2147
- this.sortChange.emit({ key: this.currentSortField, order: this.currentSortOrder });
2148
- }
2149
- /**
2150
- * Handles cell click events.
2151
- *
2152
- * Emits cellClick event and handles row selection if selection mode is enabled.
2153
- * Updates the selection state and emits selectChange event accordingly.
2154
- *
2155
- * @param row - Data row that was clicked
2156
- * @param col - Column configuration of the clicked cell
2157
- * @param index - Row index in the dataset
2158
- * @param event
2159
- */
2160
- onCellClick(row, col, index, event) {
2161
- this.cellClick.emit({ row, col, index, event });
2162
- if (this.selection().mode !== 'none') {
2163
- const selected = this.selector.select(row);
2164
- this.selectChange.emit({ selected });
2165
- }
2166
- }
2167
- onCellContext(row, col, index, event) {
2168
- this.cellContext.emit({ row, col, index, event });
2169
- }
2170
- onCellDoubleClick(row, col, index, event) {
2171
- this.cellDoubleClick.emit({ row, col, index, event });
2172
- }
2173
- isExpandable(column) {
2174
- const keys = this.expanderMap();
2175
- return keys.has(column.key);
2176
- }
2177
- /**
2178
- * Handles column expand/collapse toggle.
2179
- *
2180
- * Toggles the expanded state of a column and updates the visibility
2181
- * of all dependent columns that reference this column via expandBy property.
2182
- *
2183
- * @param column - Column configuration to expand or collapse
2184
- */
2185
- onExpand(column) {
2186
- const expanded = !this.expanderMap().get(column.key);
2187
- this.expanderMap.update((prev) => {
2188
- const map = new Map(prev);
2189
- map.set(column.key, expanded);
2190
- return map;
2191
- });
2192
- const columns = this.extendedColumns().map((col) => col.expandBy === column.key ? { ...col, visible: expanded } : col);
2193
- this.vm.columns.set(columns);
2194
- }
2195
- /**
2196
- * Handles vertical scroll events and updates visible rows.
2197
- *
2198
- * Implements virtual scrolling by calculating which rows should be rendered
2199
- * based on the current scroll position. Also handles infinite scroll data loading
2200
- * when the user scrolls near the end of available data.
2201
- *
2202
- * @param initial - Whether this is the initial scroll calculation
2203
- */
2204
- onVerticalScroll(initial = false) {
2205
- const el = this.scrollEl()?.nativeElement;
2206
- if (!el)
2207
- return;
2208
- const scrollTop = el.scrollTop ?? 0;
2209
- const viewportHeight = el.clientHeight ?? 0;
2210
- const data = this.data() ?? [];
2211
- const total = data.length ?? 0;
2212
- const rowHeight = Math.max(1, this.rowHeight());
2213
- const virtualBuffer = Math.max(0, this.virtualBuffer());
2214
- const pinnedTopH = this.vm.pinnedTop().length * rowHeight;
2215
- const limit = this.mode() === 'pagination';
2216
- const cap = limit ? Math.max(1, this.pageSize()) : Number.POSITIVE_INFINITY;
2217
- const viewportRows = Math.ceil(viewportHeight / rowHeight);
2218
- const visibleCount = Math.min(viewportRows + virtualBuffer, cap);
2219
- const start = Math.max(0, Math.floor(scrollTop / rowHeight) - Math.floor(virtualBuffer / 2));
2220
- const end = Math.min(total, start + visibleCount);
2221
- if (viewportHeight <= 0 || !isFinite(viewportHeight) || !isFinite(rowHeight)) {
2222
- const fallbackCount = Math.min(total, Math.max(1, this.pageSize()));
2223
- this.renderCount = fallbackCount;
2224
- this.ensureRenderSlots(fallbackCount);
2225
- this.updateStickyRow(scrollTop, rowHeight, pinnedTopH);
2226
- this.finalizeScroll();
2227
- return;
2228
- }
2229
- if (start === this.lastStartIndex && end === this.lastEndIndex) {
2230
- this.finalizeScroll();
2231
- return;
2232
- }
2233
- this.lastStartIndex = start;
2234
- this.lastEndIndex = end;
2235
- this.startIndex = start;
2236
- this.renderCount = Math.max(0, end - start);
2237
- this.ensureRenderSlots(this.renderCount);
2238
- this.updateStickyRow(scrollTop, rowHeight, pinnedTopH);
2239
- if (!initial && this.mode() === 'infinity') {
2240
- const threshold = Math.max(0, total - Math.max(1, Math.floor(visibleCount * 1.5)));
2241
- const nearEnd = start + visibleCount >= threshold;
2242
- if (nearEnd && !this.loading()) {
2243
- const modifier = this.pageStartFromZero() ? 0 : 1;
2244
- const page = Math.floor(total / this.pageSize()) + modifier;
2245
- if (this.lastInfinityPageRequested === page && this.lastInfinityTotal === total) {
2246
- return;
2247
- }
2248
- this.lastInfinityTotal = total;
2249
- this.lastInfinityPageRequested = page;
2250
- this.pageChange.emit({ page, rows: this.pageSize() });
2251
- }
2252
- }
2253
- this.finalizeScroll();
2254
- }
2255
- onHorizontalScroll() { }
2256
- /**
2257
- * Handles mouse down event on scrollbar thumb for drag scrolling.
2258
- *
2259
- * Initiates dragging mode and sets up mouse move/up event listeners
2260
- * to track thumb position and update scroll position accordingly.
2261
- * Automatically cleans up listeners when dragging ends.
2262
- *
2263
- * @param e - Mouse down event from a scrollbar thumb element
2264
- */
2265
- onThumbDown(e) {
2266
- e.preventDefault();
2267
- e.stopPropagation();
2268
- const el = this.scrollEl()?.nativeElement;
2269
- if (!el)
2270
- return;
2271
- this.vm.dragging = true;
2272
- this.showScrollbar();
2273
- const startY = e.clientY;
2274
- const startTop = this.vm.thumbTopPx();
2275
- const state = computeScrollbarState(el.scrollHeight || 1, el.clientHeight || 1, el.scrollTop || 0);
2276
- const maxThumbTop = state.maxThumbTop || 1;
2277
- const maxScrollTop = state.maxScrollTop || 1;
2278
- const onMove = (ev) => {
2279
- const delta = ev.clientY - startY;
2280
- const newTop = clampThumbTop(startTop + delta, maxThumbTop);
2281
- this.vm.thumbTopPx.set(newTop);
2282
- el.scrollTop = mapThumbTopToScrollTop(newTop, maxThumbTop, maxScrollTop);
2283
- this.vm.calcScrollbar();
2284
- this.showScrollbar();
2285
- };
2286
- const onUp = () => {
2287
- window.removeEventListener('mousemove', onMove);
2288
- window.removeEventListener('mouseup', onUp);
2289
- this.vm.dragging = false;
2290
- this.hideScrollbarSoon();
2291
- };
2292
- window.addEventListener('mousemove', onMove);
2293
- window.addEventListener('mouseup', onUp);
2294
- }
2295
- showScrollbar() {
2296
- this.vm.scrollbarVisible.set(true);
2297
- clearTimeout(this.hideSbTimeout);
2298
- }
2299
- hideScrollbarSoon(delay = 1200) {
2300
- if (this.vm.dragging) {
2301
- return;
2302
- }
2303
- clearTimeout(this.hideSbTimeout);
2304
- this.hideSbTimeout = setTimeout(() => this.vm.scrollbarVisible.set(false), delay);
2305
- }
2306
- trackPinnedRow = (row) => row.order;
2307
- cellClass(col, row) {
2308
- if (typeof col.cellClass === 'function') {
2309
- return col.cellClass(row);
2310
- }
2311
- return col.cellClass;
2312
- }
2313
- ariaSort(col) {
2314
- if (this.currentSortField !== col.sortKey) {
2315
- return 'none';
2316
- }
2317
- return this.currentSortOrder === 'asc' ? 'ascending' : 'descending';
2318
- }
2319
- resolveTooltip(row, col) {
2320
- const tooltip = col.tooltip;
2321
- if (!tooltip) {
2322
- return null;
2323
- }
2324
- if (typeof tooltip === 'function') {
2325
- const value = tooltip(row);
2326
- if (value === null || value === undefined || value === '') {
2327
- return null;
2328
- }
2329
- return String(value);
2330
- }
2331
- if (typeof tooltip === 'string') {
2332
- return tooltip === '' ? null : tooltip;
2333
- }
2334
- return tooltip;
2335
- }
2336
- showTooltip(event, row, col, index) {
2337
- const resolved = this.resolveTooltip(row, col);
2338
- if (!resolved) {
2339
- return;
2340
- }
2341
- const baseValue = 'value' in col ? col.value(row) : row[col.key];
2342
- const ctx = {
2343
- $implicit: row,
2344
- row,
2345
- col: col,
2346
- index,
2347
- value: baseValue,
2348
- };
2349
- const offset = 12;
2350
- const x = event.clientX + offset;
2351
- const y = event.clientY + offset;
2352
- if (typeof resolved === 'string') {
2353
- this.tooltipState.set({ text: resolved, x, y, visible: true });
2354
- }
2355
- else {
2356
- this.tooltipState.set({ tpl: resolved, ctx, x, y, visible: true });
2357
- }
2358
- requestAnimationFrame(() => this.positionTooltip());
2359
- }
2360
- hideTooltip() {
2361
- if (!this.tooltipState().visible) {
2362
- return;
2363
- }
2364
- this.tooltipState.update((prev) => ({ ...prev, visible: false }));
2365
- }
2366
- isStickyRowIndex(index) {
2367
- return this.stickyRowIndex() === index;
2368
- }
2369
- resolveRowTemplate(row, index) {
2370
- const resolver = this.getRowTemplate();
2371
- if (resolver) {
2372
- const resolved = resolver(row, index);
2373
- if (resolved) {
2374
- return resolved;
2375
- }
2376
- }
2377
- return this.rowTpl()?.tpl ?? null;
2378
- }
2379
- initVm() {
2380
- this.vm.scrollEl.set(this.scrollEl());
2381
- this.vm.columns.set(this.extendedColumns());
2382
- this.vm.pinnedRows.set(this.pinnedRows());
2383
- this.vm.headerGroups.set(this.headerGroups());
2384
- queueMicrotask(() => this.initHeader());
2385
- }
2386
- initSelector() {
2387
- this.selector.data.set(this.data());
2388
- this.selector.selection.set(this.selection());
2389
- }
2390
- initRefs() {
2391
- this.vm.globalTypeCellTpls.clear();
2392
- this.vm.globalDataCellTpls.clear();
2393
- this.vm.globalRowCellTpls.clear();
2394
- this.cellTypedSlotRefs()?.forEach((dir) => this.vm.globalTypeCellTpls.set(dir.type(), dir.tpl));
2395
- this.cellDataSlotRefs()?.forEach((dir) => this.vm.globalDataCellTpls.set(dir.key(), dir.tpl));
2396
- this.declarativeColumns().rowCellTemplatesByKey.forEach((tpl, key) => this.vm.globalRowCellTpls.set(key, tpl));
2397
- const headerMap = new Map();
2398
- this.headerSlotRefs()?.forEach((h) => headerMap.set(h.key(), h.tpl));
2399
- this.extendedColumns()?.forEach((c) => {
2400
- if (!c.headerTemplate && headerMap.has(c.key)) {
2401
- c.headerTemplate = headerMap.get(c.key);
2402
- }
2403
- });
2404
- }
2405
- initSort() {
2406
- const firstSortable = this.extendedColumns()?.find((c) => !!c.sortKey);
2407
- if (firstSortable) {
2408
- this.currentSortField = firstSortable.sortKey;
2409
- this.currentSortOrder = 'asc';
2410
- }
2411
- }
2412
- initHeader() {
2413
- const el = this.headerEl()?.nativeElement;
2414
- if (!el)
2415
- return;
2416
- this.headerHeight.set(el.offsetHeight);
2417
- }
2418
- initScroll() {
2419
- const scrollEl = this.scrollEl()?.nativeElement;
2420
- if (scrollEl) {
2421
- const scrollDetector = new ScrollDirectionDetector(scrollEl);
2422
- this.ngZone.runOutsideAngular(() => {
2423
- this.subscription.add(fromEvent(scrollEl, 'scroll').subscribe(() => this.scheduleScrollTick(scrollDetector)));
2424
- this.subscription.add(fromEvent(scrollEl, 'scroll').subscribe(() => this.scheduleStickyUpdate()));
2425
- });
2426
- }
2427
- queueMicrotask(() => this.onVerticalScroll(true));
2428
- }
2429
- initObserver() {
2430
- const root = this.rootEl();
2431
- if (!root)
2432
- return;
2433
- this.subscription.add(this.resizeSubject.pipe(debounceTime(this.defaults.debounce.resize)).subscribe((entries) => {
2434
- const rect = entries[0].contentRect;
2435
- const width = rect.width;
2436
- const height = rect.height;
2437
- const widthChanged = width !== this.lastResizeWidth;
2438
- const heightChanged = height !== this.lastResizeHeight;
2439
- if (!widthChanged && !heightChanged) {
2440
- return;
2441
- }
2442
- this.lastResizeWidth = width;
2443
- this.lastResizeHeight = height;
2444
- if (widthChanged) {
2445
- this.vm.containerWidth.set(width);
2446
- queueMicrotask(() => this.initHeader());
2447
- }
2448
- if (heightChanged) {
2449
- this.onVerticalScroll(true);
2450
- }
2451
- }));
2452
- this.observer = new ResizeObserver((entries) => this.resizeSubject.next(entries));
2453
- this.observer.observe(root.nativeElement);
2454
- }
2455
- initExpander() {
2456
- const map = new Map();
2457
- const columns = untracked(() => this.vm.columns().map((col) => {
2458
- col.expandBy && map.set(col.expandBy, false);
2459
- return { ...col, visible: col.expandBy ? false : col.visible };
2460
- }));
2461
- this.vm.columns.set(columns);
2462
- this.expanderMap.set(map);
2463
- }
2464
- positionTooltip() {
2465
- const el = this.tooltipEl()?.nativeElement;
2466
- const state = this.tooltipState();
2467
- if (!el || !state.visible) {
2468
- return;
2469
- }
2470
- const rect = el.getBoundingClientRect();
2471
- const padding = 8;
2472
- const vw = window.innerWidth;
2473
- const vh = window.innerHeight;
2474
- let x = state.x;
2475
- let y = state.y;
2476
- if (x + rect.width + padding > vw) {
2477
- x = Math.max(padding, vw - rect.width - padding);
2478
- }
2479
- if (y + rect.height + padding > vh) {
2480
- y = Math.max(padding, vh - rect.height - padding);
2481
- }
2482
- if (x !== state.x || y !== state.y) {
2483
- this.tooltipState.update((prev) => ({ ...prev, x, y }));
2484
- }
2485
- }
2486
- scheduleScrollbarUpdate() {
2487
- if (this.scrollbarRafId !== null) {
2488
- return;
2489
- }
2490
- this.scrollbarRafId = requestAnimationFrame(() => {
2491
- this.scrollbarRafId = null;
2492
- this.vm.calcScrollbar();
2493
- });
2494
- }
2495
- finalizeScroll() {
2496
- this.scheduleScrollbarUpdate();
2497
- this.showScrollbar();
2498
- this.hideScrollbarSoon();
2499
- }
2500
- scheduleScrollTick(detector) {
2501
- if (this.scrollRafId !== null) {
2502
- return;
2503
- }
2504
- this.scrollRafId = requestAnimationFrame(() => {
2505
- this.scrollRafId = null;
2506
- const direction = detector.detect();
2507
- this.ngZone.run(() => {
2508
- direction === 'vertical' ? this.onVerticalScroll() : this.onHorizontalScroll();
2509
- this.hideTooltip();
2510
- });
2511
- });
2512
- }
2513
- clearScrollRaf() {
2514
- if (this.scrollRafId !== null) {
2515
- cancelAnimationFrame(this.scrollRafId);
2516
- this.scrollRafId = null;
2517
- }
2518
- }
2519
- ensureRenderSlots(count) {
2520
- const current = this.renderSlots();
2521
- if (current.length === count) {
2522
- return;
2523
- }
2524
- const next = new Array(count);
2525
- for (let i = 0; i < count; i++) {
2526
- next[i] = i;
2527
- }
2528
- this.renderSlots.set(next);
2529
- }
2530
- clearScrollbarRaf() {
2531
- if (this.scrollbarRafId !== null) {
2532
- cancelAnimationFrame(this.scrollbarRafId);
2533
- this.scrollbarRafId = null;
2534
- }
2535
- }
2536
- scheduleStickyUpdate() {
2537
- if (this.stickyRafId !== null) {
2538
- return;
2539
- }
2540
- this.stickyRafId = requestAnimationFrame(() => {
2541
- this.stickyRafId = null;
2542
- this.ngZone.run(() => this.updateStickyFromScroll());
2543
- });
2544
- }
2545
- clearStickyRaf() {
2546
- if (this.stickyRafId !== null) {
2547
- cancelAnimationFrame(this.stickyRafId);
2548
- this.stickyRafId = null;
2549
- }
2550
- }
2551
- updateStickyRow(scrollTop, rowHeight, pinnedTopH) {
2552
- const indexes = this.stickyIndexes();
2553
- if (!indexes.length) {
2554
- this.stickyRowIndex.set(null);
2555
- return;
2556
- }
2557
- const scrollRowIndex = Math.max(0, Math.floor(scrollTop / rowHeight));
2558
- const currentIndex = this.findStickyIndexBefore(indexes, scrollRowIndex);
2559
- if (currentIndex === null) {
2560
- this.stickyRowIndex.set(null);
2561
- return;
2562
- }
2563
- let activeIndex = currentIndex;
2564
- const prevIndex = this.stickyRowIndex();
2565
- const hysteresisPx = Math.max(1, rowHeight * 0.5);
2566
- if (prevIndex !== null && prevIndex !== currentIndex) {
2567
- const boundaryPx = currentIndex * rowHeight;
2568
- const delta = Math.abs(scrollTop - boundaryPx);
2569
- if (delta < hysteresisPx) {
2570
- activeIndex = prevIndex;
2571
- }
2572
- }
2573
- const stickyTop = this.headerHeight() + pinnedTopH;
2574
- const topPx = scrollTop + stickyTop;
2575
- this.stickyRowIndex.set(activeIndex);
2576
- this.stickyRowTopPx.set(topPx);
2577
- }
2578
- updateStickyFromScroll() {
2579
- const el = this.scrollEl()?.nativeElement;
2580
- if (!el)
2581
- return;
2582
- const scrollTop = el.scrollTop ?? 0;
2583
- const rowHeight = Math.max(1, this.rowHeight());
2584
- const pinnedTopH = this.vm.pinnedTop().length * rowHeight;
2585
- this.updateStickyRow(scrollTop, rowHeight, pinnedTopH);
2586
- }
2587
- findStickyIndexBefore(indexes, index) {
2588
- let low = 0;
2589
- let high = indexes.length - 1;
2590
- let result = -1;
2591
- while (low <= high) {
2592
- const mid = (low + high) >>> 1;
2593
- const value = indexes[mid];
2594
- if (value <= index) {
2595
- result = value;
2596
- low = mid + 1;
2597
- }
2598
- else {
2599
- high = mid - 1;
2600
- }
2601
- }
2602
- return result === -1 ? null : result;
2603
- }
2604
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
2605
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DataGrid, isStandalone: true, selector: "re-data-grid", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, pinnedRows: { classPropertyName: "pinnedRows", publicName: "pinnedRows", isSignal: true, isRequired: false, transformFunction: null }, isRowSticky: { classPropertyName: "isRowSticky", publicName: "isRowSticky", isSignal: true, isRequired: false, transformFunction: null }, getRowTemplate: { classPropertyName: "getRowTemplate", publicName: "getRowTemplate", isSignal: true, isRequired: false, transformFunction: null }, hasIndexColumn: { classPropertyName: "hasIndexColumn", publicName: "hasIndexColumn", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, virtualBuffer: { classPropertyName: "virtualBuffer", publicName: "virtualBuffer", isSignal: true, isRequired: false, transformFunction: null }, lockVerticalScroll: { classPropertyName: "lockVerticalScroll", publicName: "lockVerticalScroll", isSignal: true, isRequired: false, transformFunction: null }, headerGroups: { classPropertyName: "headerGroups", publicName: "headerGroups", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingMode: { classPropertyName: "loadingMode", publicName: "loadingMode", isSignal: true, isRequired: false, transformFunction: null }, deferContent: { classPropertyName: "deferContent", publicName: "deferContent", isSignal: true, isRequired: false, transformFunction: null }, deferHeader: { classPropertyName: "deferHeader", publicName: "deferHeader", isSignal: true, isRequired: false, transformFunction: null }, deferPinned: { classPropertyName: "deferPinned", publicName: "deferPinned", isSignal: true, isRequired: false, transformFunction: null }, deferCells: { classPropertyName: "deferCells", publicName: "deferCells", isSignal: true, isRequired: false, transformFunction: null }, deferIcons: { classPropertyName: "deferIcons", publicName: "deferIcons", isSignal: true, isRequired: false, transformFunction: null }, deferTooltip: { classPropertyName: "deferTooltip", publicName: "deferTooltip", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, pageStartFromZero: { classPropertyName: "pageStartFromZero", publicName: "pageStartFromZero", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", sortChange: "sortChange", selectChange: "selectChange", rowClick: "rowClick", rowContext: "rowContext", rowDoubleClick: "rowDoubleClick", cellClick: "cellClick", cellContext: "cellContext", cellDoubleClick: "cellDoubleClick" }, providers: [DataGridVm], queries: [{ propertyName: "cellTypedSlotRefs", predicate: DataGridTypeCellTemplateDirective, isSignal: true }, { propertyName: "cellDataSlotRefs", predicate: DataGridCellTemplateDirective, isSignal: true }, { propertyName: "declarativeColumnRefs", predicate: DataGridDeclarativeColumn, isSignal: true }, { propertyName: "headerSlotRefs", predicate: DataGridHeaderTemplateDirective, isSignal: true }, { propertyName: "emptySlotRefs", predicate: DataGridCellEmptyDirective, isSignal: true }, { propertyName: "loadingSlotRefs", predicate: DataGridCellLoadingDirective, isSignal: true }, { propertyName: "sortIcSlotRefs", predicate: DataGridSortIconDirective, isSignal: true }, { propertyName: "expanderIcSlotRefs", predicate: DataGridExpanderIconDirective, isSignal: true }, { propertyName: "stickyRowSlotRefs", predicate: DataGridStickyRowDirective, isSignal: true }, { propertyName: "rowSlotRefs", predicate: DataGridRowDirective, isSignal: true }], viewQueries: [{ propertyName: "rootEl", first: true, predicate: ["root"], descendants: true, isSignal: true }, { propertyName: "scrollEl", first: true, predicate: ["scroll"], descendants: true, isSignal: true }, { propertyName: "headerEl", first: true, predicate: ["header"], descendants: true, isSignal: true }, { propertyName: "tooltipEl", first: true, predicate: ["tooltip"], descendants: true, isSignal: true }], ngImport: i0, template: "@let items = data();\r\n@let empty = !loading() && !items?.length;\r\n@let notEmpty = !!items?.length;\r\n@let skeletonRowsCount = 4;\r\n@let skeletonMode = loadingMode() === 'skeleton';\r\n@let spinnerMode = loadingMode() === 'spinner';\r\n@let showInfinitySkeleton = loading() && skeletonMode && mode() === 'infinity';\r\n@let showPaginationSkeleton = loading() && skeletonMode && mode() === 'pagination' && !notEmpty;\r\n@let showSpinnerLoading = loading() && spinnerMode;\r\n@let extraInfinitySkeletonRows = showInfinitySkeleton ? skeletonRowsCount : 0;\r\n\r\n@let pinnedTopH = vm.pinnedTop().length * rowHeight();\r\n@let pinnedBottomH = vm.pinnedBottom().length * rowHeight();\r\n@let rowH = rowHeight();\r\n@let contentW = vm.contentWidth();\r\n@let cols = vm.columnsToShow();\r\n@let stickyTop = pinnedTopH + headerHeight();\r\n@let normalizedHeaderGroups = vm.normalizedHeaderGroups();\r\n@let stickyRow = stickyRowData();\r\n@let stickyIndex = stickyRowIndex();\r\n\r\n<div\r\n #root\r\n class=\"re-dg-root\"\r\n [class.loading]=\"showSpinnerLoading\"\r\n [class.lock-vertical-scroll]=\"lockVerticalScroll()\"\r\n [style.height]=\"styleHeight()\"\r\n role=\"table\"\r\n>\r\n @if (showSpinnerLoading) {\r\n <div class=\"re-dg-loader\">\r\n @let loadingTemplate = loadingTpl();\r\n\r\n @if (loadingTemplate?.tpl) {\r\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\r\n } @else {\r\n <span class=\"re-dg-loader-spinner\" aria-label=\"Loading\"></span>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n #scroll\r\n class=\"re-dg-body\"\r\n role=\"rowgroup\"\r\n (mouseenter)=\"showScrollbar()\"\r\n (mouseleave)=\"hideScrollbarSoon()\"\r\n >\r\n <ng-template #headerContent>\r\n <div\r\n class=\"re-dg-header\"\r\n role=\"rowgroup\"\r\n [style.width.px]=\"vm.contentWidth()\"\r\n [style.min-width.%]=\"100\"\r\n >\r\n <div #header class=\"re-dg-header-rows\">\r\n @if (normalizedHeaderGroups.length) {\r\n <div class=\"re-dg-row re-dg-header-group-row\" role=\"row\" [style.width.px]=\"vm.contentWidth()\" [style.min-width.%]=\"100\">\r\n @for (group of normalizedHeaderGroups; track group.key) {\r\n @let groupStickyLeft = !!group.startKey && !!group.endKey && vm.isStickyLeft(group.startKey) && vm.isStickyLeft(group.endKey);\r\n @let groupStickyRight = !!group.startKey && !!group.endKey && vm.isStickyRight(group.startKey) && vm.isStickyRight(group.endKey);\r\n\r\n <div\r\n class=\"re-dg-header-cell re-dg-header-group-cell\"\r\n role=\"columnheader\"\r\n [class.sticky-left]=\"groupStickyLeft\"\r\n [class.sticky-right]=\"groupStickyRight\"\r\n [style.left.px]=\"groupStickyLeft && group.startKey ? vm.stickyOffset(group.startKey, 'left') : null\"\r\n [style.right.px]=\"groupStickyRight && group.endKey ? vm.stickyOffset(group.endKey, 'right') : null\"\r\n [style.width.px]=\"group.widthPx\"\r\n [style.justify-content]=\"group.align || 'left'\"\r\n [title]=\"group.title || ''\"\r\n >\r\n @if (group.titleTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"group.titleTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: group.title || '' }\"\r\n />\r\n } @else {\r\n <span class=\"re-dg-header-text\">{{ group.title || '' }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"re-dg-row re-dg-header-row\" role=\"row\" [style.width.px]=\"vm.contentWidth()\" [style.min-width.%]=\"100\">\r\n @for (col of vm.columnsToShow(); track col.key) {\r\n <div\r\n class=\"re-dg-header-cell\"\r\n role=\"columnheader\"\r\n [class.sortable]=\"!!col.sortKey\"\r\n [class.active-sort]=\"currentSortField && (currentSortField === col.sortKey)\"\r\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\r\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\r\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\r\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [style.min-width.px]=\"col.minWidth || null\"\r\n [style.max-width.px]=\"col.maxWidth || null\"\r\n [style.justify-content]=\"col.align || 'left'\"\r\n [attr.aria-sort]=\"ariaSort(col)\"\r\n [attr.tabindex]=\"col.sortKey ? 0 : -1\"\r\n [title]=\"col.header\"\r\n (click)=\"col.sortKey && onSort(col)\"\r\n (keydown.enter)=\"col.sortKey && onSort(col)\"\r\n >\r\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\r\n @let isMultiSelect = selection().mode === 'multi';\r\n\r\n @if (isCheckbox && isMultiSelect) {\r\n @if (deferIcons()) {\r\n @defer (when true) {\r\n <re-checkbox-ic [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\r\n } @placeholder {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n } @loading {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n }\r\n } @else {\r\n <re-checkbox-ic [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\r\n }\r\n } @else {\r\n @if (col.headerTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"col.headerTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: col.header }\"\r\n />\r\n } @else {\r\n <span class=\"re-dg-header-text\">{{ col.header }}</span>\r\n }\r\n }\r\n\r\n @if (col.sortKey) {\r\n <span class=\"re-dg-sort-ind\">\r\n @let direction = currentSortField === col.sortKey ? currentSortOrder : undefined;\r\n\r\n @if (sortTpl()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"sortTpl()!.tpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: direction }\"\r\n />\r\n } @else {\r\n @if (deferIcons()) {\r\n @defer (when true) {\r\n <re-sort-ic [direction]=\"direction\" />\r\n } @placeholder {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n } @loading {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n }\r\n } @else {\r\n <re-sort-ic [direction]=\"direction\" />\r\n }\r\n }\r\n </span>\r\n }\r\n\r\n @if (isExpandable(col)) {\r\n <button (click)=\"$event.stopPropagation(); onExpand(col)\">\r\n @let expanded = expanderMap().get(col.key);\r\n\r\n @if (expanderTpl()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"expanderTpl()!.tpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: expanded }\" />\r\n } @else {\r\n @if (deferIcons()) {\r\n @defer (when true) {\r\n <re-expand-ic [expanded]=\"expanded\" />\r\n } @placeholder {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n } @loading {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n }\r\n } @else {\r\n <re-expand-ic [expanded]=\"expanded\" />\r\n }\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- PINNED TOP ROWS -->\r\n @if (notEmpty) {\r\n <ng-template #pinnedTopContent>\r\n @for (pr of vm.pinnedTop(); track trackPinnedRow(pr)) {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-top\" role=\"row\" [style.width.px]=\"contentW\" [style.min-width.%]=\"100\">\r\n @if (pr.rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n } @else {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pinnedRowCells\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n }\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n @if (deferPinned()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"pinnedTopContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-top re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n } @loading {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-top re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"pinnedTopContent\" />\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n\r\n @if (deferHeader()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"headerContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-header re-dg-deferred-placeholder\" [style.min-height.px]=\"headerHeight()\"></div>\r\n } @loading {\r\n <div class=\"re-dg-header re-dg-deferred-placeholder\" [style.min-height.px]=\"headerHeight()\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"headerContent\" />\r\n }\r\n\r\n <ng-template #dataCellContent let-row let-col=\"col\" let-index=\"index\">\r\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\r\n\r\n @if (isCheckbox) {\r\n <re-checkbox-ic [state]=\"selector.isSelected(row)\" />\r\n } @else {\r\n @if (deferCells()) {\r\n @defer (when true) {\r\n <re-data-grid-cell [index]=\"index\" [item]=\"row\" [column]=\"col\" />\r\n } @placeholder {\r\n <span class=\"re-dg-cell-deferred\"></span>\r\n } @loading {\r\n <span class=\"re-dg-cell-deferred\"></span>\r\n }\r\n } @else {\r\n <re-data-grid-cell [index]=\"index\" [item]=\"row\" [column]=\"col\" />\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-template #gridContent>\r\n\r\n <!-- STICKY ROW -->\r\n @if (stickyRow && stickyIndex !== null) {\r\n <div\r\n class=\"re-dg-row re-dg-data-row re-dg-sticky-row\"\r\n role=\"row\"\r\n [style.width.px]=\"vm.contentWidth()\"\r\n [style.min-width.%]=\"100\"\r\n [style.height.px]=\"rowHeight()\"\r\n [style.top.px]=\"stickyRowTopPx()\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"$event.stopPropagation(); rowClick.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n (contextmenu)=\"$event.stopPropagation(); rowContext.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n (dblclick)=\"$event.stopPropagation(); rowDoubleClick.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n >\r\n @let stickyTemplate = stickyRowTpl();\r\n @let rowTemplate = resolveRowTemplate(stickyRow, stickyIndex);\r\n\r\n @if (stickyTemplate?.tpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"stickyTemplate!.tpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: stickyRow, index: stickyIndex }\"\r\n />\r\n } @else if (rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: stickyRow,\r\n index: stickyIndex,\r\n columns: vm.columnsToShow(),\r\n rowHeight: rowHeight(),\r\n isSticky: true\r\n }\"\r\n />\r\n } @else {\r\n @for (col of vm.columnsToShow(); track col.key) {\r\n <div\r\n class=\"re-dg-cell\"\r\n role=\"cell\"\r\n [class.expanded]=\"!!col.expandBy\"\r\n [class]=\"cellClass(col, stickyRow)\"\r\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\r\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\r\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\r\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\r\n [style.justify-items]=\"col.align || 'left'\"\r\n [style.text-align]=\"col.align || 'left'\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [attr.tabindex]=\"0\"\r\n (mouseenter)=\"showTooltip($event, stickyRow, col, stickyIndex)\"\r\n (mouseleave)=\"hideTooltip()\"\r\n (click)=\"onCellClick(stickyRow, col, stickyIndex, $event);\"\r\n (contextmenu)=\"onCellContext(stickyRow, col, stickyIndex, $event)\"\r\n (dblclick)=\"onCellDoubleClick(stickyRow, col, stickyIndex, $event)\"\r\n (keydown.enter)=\"onCellClick(stickyRow, col, stickyIndex, $event)\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"dataCellContent\"\r\n [ngTemplateOutletContext]=\"{ $implicit: stickyRow, col: col, index: stickyIndex }\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n @if (empty) {\r\n @let emptyTemplate = emptyTpl()?.tpl;\r\n\r\n <div class=\"re-dg-empty\">\r\n @if (emptyTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"emptyTemplate\" />\r\n } @else {\r\n <span class=\"re-dg-empty-text\">{{ defaults.translations.emptyState }}</span>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Content -->\r\n @if (notEmpty) {\r\n <div\r\n class=\"re-dg-spacer\"\r\n [style.width.px]=\"contentW\"\r\n [style.height.px]=\"(items.length + extraInfinitySkeletonRows) * rowH - pinnedBottomH\"></div>\r\n\r\n @for (slot of renderSlots(); track slot) {\r\n @let rowIndex = startIndex + slot;\r\n @let row = items[rowIndex];\r\n @let rowTemplate = row ? resolveRowTemplate(row, rowIndex) : null;\r\n\r\n @if (row && !isStickyRowIndex(rowIndex)) {\r\n <div\r\n class=\"re-dg-row re-dg-data-row\"\r\n role=\"row\"\r\n [style.width.px]=\"contentW\"\r\n [style.min-width.%]=\"100\"\r\n [style.height.px]=\"rowH\"\r\n [style.transform]=\"'translateY(' + (rowIndex * rowH + stickyTop) + 'px)'\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"$event.stopPropagation(); rowClick.emit({ row, index: rowIndex, event: $event })\"\r\n (contextmenu)=\"$event.stopPropagation(); rowContext.emit({ row, index: rowIndex, event: $event })\"\r\n (dblclick)=\"$event.stopPropagation(); rowDoubleClick.emit({ row, index: rowIndex, event: $event })\"\r\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row, index: rowIndex, event: $event })\"\r\n >\r\n @if (rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: row,\r\n index: rowIndex,\r\n columns: vm.columnsToShow(),\r\n rowHeight: rowHeight(),\r\n isSticky: false\r\n }\"\r\n />\r\n } @else {\r\n @for (col of cols; track col.key) {\r\n @let stickyLeft = vm.stickyOffset(col.key, 'left');\r\n @let stickyRight = vm.stickyOffset(col.key, 'right');\r\n @let isLeft = vm.isStickyLeft(col.key);\r\n @let isRight = vm.isStickyRight(col.key);\r\n\r\n <div\r\n class=\"re-dg-cell\"\r\n role=\"cell\"\r\n [class.expanded]=\"!!col.expandBy\"\r\n [class]=\"cellClass(col, row)\"\r\n [class.sticky-left]=\"isLeft\"\r\n [class.sticky-right]=\"isRight\"\r\n [style.left.px]=\"stickyLeft\"\r\n [style.right.px]=\"stickyRight\"\r\n [style.justify-items]=\"col.align || 'left'\"\r\n [style.text-align]=\"col.align || 'left'\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [attr.tabindex]=\"0\"\r\n (mouseenter)=\"showTooltip($event, row, col, rowIndex)\"\r\n (mouseleave)=\"hideTooltip()\"\r\n (click)=\"onCellClick(row, col, rowIndex, $event);\"\r\n (contextmenu)=\"onCellContext(row, col, rowIndex, $event)\"\r\n (dblclick)=\"onCellDoubleClick(row, col, rowIndex, $event)\"\r\n (keydown.enter)=\"onCellClick(row, col, rowIndex, $event)\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"dataCellContent\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, col: col, index: rowIndex }\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n\r\n @if (showInfinitySkeleton || showPaginationSkeleton) {\r\n @let loadingTemplate = loadingTpl();\r\n\r\n @if (loadingTemplate?.tpl) {\r\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\r\n } @else {\r\n @for (si of [0, 1, 2, 3]; track si) {\r\n <div\r\n class=\"re-dg-row re-dg-data-row re-dg-skeleton-row\"\r\n role=\"row\"\r\n [style.width.px]=\"contentW\"\r\n [style.min-width.%]=\"100\"\r\n [style.height.px]=\"rowH\"\r\n [style.transform]=\"'translateY(' + (((showInfinitySkeleton ? items.length : 0) + si) * rowH + stickyTop) + 'px)'\"\r\n >\r\n <span class=\"re-dg-skeleton-row-line\"></span>\r\n </div>\r\n }\r\n }\r\n }\r\n\r\n <!-- PINNED BOTTOM ROWS -->\r\n @if (notEmpty) {\r\n <ng-template #pinnedBottomContent>\r\n <div class=\"re-dg-footer\" role=\"rowgroup\">\r\n @for (pr of vm.pinnedBottom(); track trackPinnedRow(pr)) {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-bottom\" role=\"row\" [style.width.px]=\"contentW\" [style.min-width.%]=\"100\">\r\n @if (pr.rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n } @else {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pinnedRowCells\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n\r\n @if (deferPinned()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"pinnedBottomContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-footer re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n } @loading {\r\n <div class=\"re-dg-footer re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"pinnedBottomContent\" />\r\n }\r\n }\r\n </ng-template>\r\n\r\n @if (deferContent()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"gridContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH * 3\"></div>\r\n } @loading {\r\n <div class=\"re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH * 3\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"gridContent\" />\r\n }\r\n </div>\r\n\r\n <ng-template #pinnedRowCells let-row>\n @for (col of cols; track col.key) {\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n @let isIndex = 'type' in col && col.type === 'index';\n @let stickyLeft = vm.stickyOffset(col.key, 'left');\n @let stickyRight = vm.stickyOffset(col.key, 'right');\n @let isLeft = vm.isStickyLeft(col.key);\n @let isRight = vm.isStickyRight(col.key);\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.expanded]=\"!!col.expandBy\"\n [class]=\"cellClass(col, $any(row))\"\n [class.sticky-left]=\"isLeft\"\n [class.sticky-right]=\"isRight\"\n [style.left.px]=\"stickyLeft\"\n [style.right.px]=\"stickyRight\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.text-align]=\"col.align || 'left'\"\n [style.height.px]=\"rowH\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [attr.tabindex]=\"isCheckbox || isIndex ? -1 : 0\"\n (mouseenter)=\"!isCheckbox && !isIndex && showTooltip($event, $any(row), col, -1)\"\n (mouseleave)=\"!isCheckbox && !isIndex && hideTooltip()\"\n (click)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event);\"\n (contextmenu)=\"!isCheckbox && !isIndex && onCellContext($any(row), col, -1, $event)\"\n (dblclick)=\"!isCheckbox && !isIndex && onCellDoubleClick($any(row), col, -1, $event)\"\n (keydown.enter)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event)\"\n >\n @if (!isCheckbox && !isIndex) {\n <ng-container\n [ngTemplateOutlet]=\"dataCellContent\"\n [ngTemplateOutletContext]=\"{ $implicit: $any(row), col: col, index: -1 }\"\n />\n }\n </div>\n }\n </ng-template>\n\r\n @if (deferTooltip()) {\r\n @defer (when true) {\r\n @let tooltipStateValue = tooltipState();\r\n <div\r\n class=\"re-dg-tooltip\"\r\n #tooltip\r\n [class.visible]=\"tooltipStateValue.visible\"\r\n [style.left.px]=\"tooltipStateValue.x\"\r\n [style.top.px]=\"tooltipStateValue.y\"\r\n >\r\n @if (tooltipStateValue.tpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"tooltipStateValue.tpl\"\r\n [ngTemplateOutletContext]=\"tooltipStateValue.ctx\"\r\n />\r\n } @else {\r\n {{ tooltipStateValue.text }}\r\n }\r\n </div>\r\n }\r\n } @else {\r\n @let tooltipStateValue = tooltipState();\r\n <div\r\n class=\"re-dg-tooltip\"\r\n #tooltip\r\n [class.visible]=\"tooltipStateValue.visible\"\r\n [style.left.px]=\"tooltipStateValue.x\"\r\n [style.top.px]=\"tooltipStateValue.y\"\r\n >\r\n @if (tooltipStateValue.tpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"tooltipStateValue.tpl\"\r\n [ngTemplateOutletContext]=\"tooltipStateValue.ctx\"\r\n />\r\n } @else {\r\n {{ tooltipStateValue.text }}\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Overlay scrollbar -->\r\n <div class=\"re-dg-scrollbar\" [class.visible]=\"vm.scrollbarVisible()\">\r\n <div\r\n class=\"re-dg-scrollbar-thumb\"\r\n role=\"scrollbar\"\r\n aria-orientation=\"vertical\"\r\n aria-hidden=\"false\"\r\n [style.height.px]=\"vm.thumbHeightPx()\"\r\n [style.transform]=\"'translateY(' + vm.thumbTopPx() + 'px)'\"\r\n (mousedown)=\"onThumbDown($event)\"\r\n ></div>\r\n </div>\r\n</div>\r\n", styles: [":host{--re-data-grid-min-height: 200px;--re-data-grid-height: 400px;--re-data-grid-rounded: var(--radius-md, 6px);--re-data-grid-separator-color: var(--border-color);--re-data-grid-separator: 1px solid var(--re-data-grid-separator-color);--re-data-grid-surface: var(--surface-neutral, #fff);--re-data-grid-active: var(--primary-color, #2a90f4);--re-data-grid-empty-color: #777;--re-data-grid-empty-surface: transparent;--re-data-grid-loading-color: #444;--re-data-grid-loading-surface: rgba(255, 255, 255, .5);--re-data-grid-spinner-size: 2rem;--re-data-grid-spinner-width: .25rem;--re-data-grid-spinner-track-color: rgba(0, 0, 0, .12);--re-data-grid-skeleton-width: 100%;--re-data-grid-skeleton-height: 100%;--re-data-grid-skeleton-rounded: var(--re-data-grid-rounded, .75rem);--re-data-grid-skeleton-shine: rgba(255, 255, 255, .8);--re-data-grid-skeleton-line: #e7ebf0;--re-data-grid-scrollbar-size: 4px;--re-data-grid-scrollbar-offset: 2px;--re-data-grid-scrollbar-track-rounded: .25rem;--re-data-grid-scrollbar-track-surface: transparent;--re-data-grid-scrollbar-thumb-size: 8px;--re-data-grid-scrollbar-thumb-color: rgba(0, 0, 0, .25);--re-data-grid-scrollbar-thumb-active-color: rgba(0, 0, 0, .45);--re-data-grid-scrollbar-thumb-rounded: var(--re-data-grid-scrollbar-track-rounded);--re-data-grid-tooltip-surface: #0f172a;--re-data-grid-tooltip-color: #f8fafc;--re-data-grid-tooltip-radius: .5rem;--re-data-grid-tooltip-padding: .4rem .6rem;--re-data-grid-tooltip-shadow: 0 8px 24px rgba(15, 23, 42, .25);--re-data-grid-tooltip-z: 60;--re-data-grid-header-rounded: var(--re-data-grid-rounded);--re-data-grid-header-surface: #fff;--re-data-grid-header-body-gap: 0px;--re-data-grid-header-row-height: 40px;--re-data-grid-header-row-separator-color: #ccc;--re-data-grid-header-row-separator: 1px solid var(--re-data-grid-header-row-separator-color);--re-data-grid-header-group-row-height: var(--re-data-grid-header-row-height);--re-data-grid-header-group-row-separator-color: var(--re-data-grid-header-row-separator-color);--re-data-grid-header-group-row-separator: 1px solid var(--re-data-grid-header-group-row-separator-color);--re-data-grid-header-group-cell-font-weight: var(--re-data-grid-header-cell-font-weight);--re-data-grid-header-group-cell-font-size: var(--re-data-grid-header-cell-font-size);--re-data-grid-header-group-cell-color: var(--re-data-grid-header-cell-color);--re-data-grid-header-group-cell-surface: var(--re-data-grid-header-cell-surface);--re-data-grid-header-cell-font-weight: 600;--re-data-grid-header-cell-font-size: .8rem;--re-data-grid-header-cell-color: #000;--re-data-grid-header-cell-surface: #fafafa;--re-data-grid-footer-separator-color: #ccc;--re-data-grid-footer-separator: 1px solid var(--re-data-grid-footer-separator-color);--re-data-grid-footer-surface: #fff;--re-data-grid-row-separator-color: #bbb;--re-data-grid-row-separator: 1px solid var(--re-data-grid-row-separator-color);--re-data-grid-row-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-row-hover-surface: var(--re-data-grid-cell-surface);--re-data-grid-row-hover-color: var(--re-data-grid-cell-color);--re-data-grid-row-hover-rounded: 0px;--re-data-grid-column-separator-color: transparent;--re-data-grid-column-separator: 1px solid var(--re-data-grid-column-separator-color);--re-data-grid-column-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-cell-paddings: .4rem .625rem;--re-data-grid-cell-font-weight: 400;--re-data-grid-cell-font-size: .75rem;--re-data-grid-cell-color: #000;--re-data-grid-cell-surface: #fff;--re-data-grid-sticky-header-cell-surface: #fff;--re-data-grid-sticky-cell-surface: #fdfdfd;--re-data-grid-sticky-cell-row-odd-surface: #fdfdfd;--re-data-grid-sticky-cell-left-shadow: 2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-sticky-cell-right-shadow: -2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-pinned-surface: #fcfcfc;--re-data-grid-pinned-separator-color: #eee;--re-data-grid-pinned-separator: 1px solid var(--re-data-grid-pinned-separator-color);--re-data-grid-expander-color: var(--primary-color, currentColor);--re-data-grid-expanded-color: var(--re-data-grid-cell-color, #000);--re-data-grid-expanded-surface: var(--re-data-grid-cell-surface, #fff);display:block;min-height:0;min-width:0}:host,:host *,:host *:before,:host *:after{box-sizing:border-box;outline:none}:host button{outline:none}.re-dg-root{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;min-height:var(--re-data-grid-min-height);border-radius:var(--re-data-grid-rounded);border:var(--re-data-grid-separator)}.re-dg-root.fill{display:block}.re-dg-root.loading{pointer-events:none;-webkit-user-select:none;user-select:none;cursor:wait}.re-dg-root.loading .re-dg-body{overflow:hidden}.re-dg-root.loading .re-dg-scrollbar{display:none!important}.re-dg-root.loading .re-dg-loader{pointer-events:all}.re-dg-root.lock-vertical-scroll .re-dg-body{overflow-x:auto;overflow-y:hidden}.re-dg-root.lock-vertical-scroll .re-dg-scrollbar{display:none!important}.re-dg-body{position:relative;flex:1 1 auto;min-height:0;min-width:0;height:inherit;border:var(--re-data-grid-separator);border-radius:var(--re-data-grid-rounded);background-color:var(--re-data-grid-surface);overflow:auto;scrollbar-width:auto;-ms-overflow-style:auto}.re-dg-body::-webkit-scrollbar{width:var(--re-data-grid-scrollbar-size);height:var(--re-data-grid-scrollbar-size)}.re-dg-body::-webkit-scrollbar:vertical{width:0}.re-dg-body::-webkit-scrollbar-track{border-radius:var(--re-data-grid-scrollbar-track-rounded);background:var(--re-data-grid-scrollbar-track-surface)}.re-dg-body::-webkit-scrollbar-thumb{border-radius:var(--re-data-grid-scrollbar-thumb-rounded);background:var(--re-data-grid-scrollbar-thumb-color);transition:opacity .3s ease}.re-dg-body::-webkit-scrollbar-thumb:hover{background:var(--re-data-grid-scrollbar-thumb-active-color)}.re-dg-header,.re-dg-footer{position:sticky;z-index:3}.re-dg-header{top:0;background-color:var(--re-data-grid-header-surface)}.re-dg-header-row{min-height:var(--re-data-grid-header-row-height)}.re-dg-header-group-row{min-height:var(--re-data-grid-header-group-row-height)}.re-dg-header-rows{display:flex;flex-direction:column;padding-bottom:var(--re-data-grid-header-body-gap)}.re-dg-footer{bottom:0;border-radius:0 0 var(--re-data-grid-rounded) var(--re-data-grid-rounded);background-color:var(--re-data-grid-footer-surface)}.re-dg-row{position:relative;display:flex}.re-dg-data-row{position:absolute;left:0;top:0;min-width:100%;cursor:default;will-change:transform}.re-dg-sticky-row{z-index:2;top:0}.re-dg-cell,.re-dg-header-cell{display:flex;flex:0 0 auto;align-items:center;padding:var(--re-data-grid-cell-paddings);border-right:var(--re-data-grid-column-separator);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.re-dg-cell{width:100%;border-bottom:var(--re-data-grid-row-separator);font-weight:var(--re-data-grid-cell-font-weight);font-size:var(--re-data-grid-cell-font-size);color:var(--re-data-grid-cell-color);background-color:var(--re-data-grid-cell-surface)}.re-dg-row:nth-child(odd) .re-dg-cell{background-color:var(--re-data-grid-row-odd-surface)}.re-dg-row:nth-child(odd) .re-dg-cell.sticky-left,.re-dg-row:nth-child(odd) .re-dg-cell.sticky-right{background-color:var(--re-data-grid-sticky-cell-row-odd-surface)}.re-dg-cell:nth-child(odd){background-color:var(--re-data-grid-column-odd-surface)}.re-dg-bottom>.re-dg-cell{border-top:var(--re-data-grid-footer-separator)}.re-dg-header-cell{align-items:center;gap:.75rem;border-bottom:var(--re-data-grid-header-row-separator);font-weight:var(--re-data-grid-header-cell-font-weight);font-size:var(--re-data-grid-header-cell-font-size);color:var(--re-data-grid-header-cell-color);background:var(--re-data-grid-header-cell-surface);-webkit-user-select:none;user-select:none;transition:color .3s ease-in-out}.re-dg-header-cell.re-dg-header-group-cell{border-bottom:var(--re-data-grid-header-group-row-separator);font-weight:var(--re-data-grid-header-group-cell-font-weight);font-size:var(--re-data-grid-header-group-cell-font-size);color:var(--re-data-grid-header-group-cell-color);background:var(--re-data-grid-header-group-cell-surface)}.re-dg-header-rows>.re-dg-row:first-child .re-dg-header-cell:first-child{border-radius:var(--re-data-grid-header-rounded) 0 0 0}.re-dg-header-rows>.re-dg-row:first-child .re-dg-header-cell:last-child{border-radius:0 var(--re-data-grid-header-rounded) 0 0}.re-dg-data-row:last-child .re-dg-cell:first-child{border-radius:0 0 0 var(--re-data-grid-rounded)}.re-dg-data-row:last-child .re-dg-cell:last-child{border-radius:0 0 var(--re-data-grid-rounded) 0}.re-dg-header-cell .re-dg-header-text{display:-webkit-box;max-height:2.4em;line-height:1.2;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.re-dg-row.re-dg-pinned>.re-dg-cell{border-bottom:var(--re-data-grid-pinned-separator);background-color:var(--re-data-grid-pinned-surface)}.re-dg-row .re-dg-header-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row .re-dg-header-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row.re-dg-pinned>.re-dg-cell.sticky-left,.re-dg-row.re-dg-pinned>.re-dg-cell.sticky-right{background-color:var(--re-data-grid-pinned-surface)}.re-dg-row:hover>.re-dg-cell,.re-dg-row:hover>.re-dg-cell.sticky-left,.re-dg-row:hover>.re-dg-cell.sticky-right{background-color:var(--re-data-grid-row-hover-surface)!important;color:var(--re-data-grid-row-hover-color)!important}.re-dg-row:hover>.re-dg-cell:first-child{border-radius:var(--re-data-grid-row-hover-rounded) 0 0 var(--re-data-grid-row-hover-rounded)}.re-dg-row:hover>.re-dg-cell:last-child{border-radius:0 var(--re-data-grid-row-hover-rounded) var(--re-data-grid-row-hover-rounded) 0}.sticky-left,.sticky-right{position:sticky;z-index:2}.sortable{cursor:pointer}.active-sort{color:var(--re-data-grid-active)}.re-dg-sort-ind{margin-left:6px}.re-dg-icon-placeholder{display:inline-block;width:1rem;height:1rem}.re-dg-cell-deferred{display:block;width:100%;height:100%}.re-dg-deferred-placeholder{background:transparent}.re-dg-data-row .re-dg-cell.expanded{color:var(--re-data-grid-expanded-color);background:var(--re-data-grid-expanded-surface)}.re-dg-empty{position:absolute;inset:0;display:grid;place-items:center;height:inherit;width:100%;border-radius:var(--re-data-grid-rounded);color:var(--re-data-grid-empty-color);background:var(--re-data-grid-empty-surface)}.re-dg-empty-text{width:100%;text-align:center}.re-dg-loader{position:absolute;inset:0;display:grid;place-items:center;height:inherit;border-radius:var(--re-data-grid-rounded);background-color:var(--re-data-grid-loading-surface);color:var(--re-data-grid-loading-color);z-index:5}.re-dg-tooltip{position:fixed;left:0;top:0;max-width:min(28rem,70vw);padding:var(--re-data-grid-tooltip-padding);border-radius:var(--re-data-grid-tooltip-radius);background:var(--re-data-grid-tooltip-surface);color:var(--re-data-grid-tooltip-color);box-shadow:var(--re-data-grid-tooltip-shadow);font-size:.75rem;line-height:1.2;z-index:var(--re-data-grid-tooltip-z);pointer-events:none;opacity:0;transform:translateY(4px);transition:opacity .12s ease,transform .12s ease}.re-dg-tooltip.visible{opacity:1;transform:translateY(0)}.re-dg-loader-spinner{width:var(--re-data-grid-spinner-size);height:var(--re-data-grid-spinner-size);border-radius:50%;border:var(--re-data-grid-spinner-width) solid var(--re-data-grid-spinner-track-color);border-top-color:var(--re-data-grid-loading-color);animation:re-dg-spinner .8s linear infinite}.re-dg-skeleton-row{display:flex;align-items:center;padding:var(--re-data-grid-cell-paddings);border-bottom:var(--re-data-grid-row-separator);background-color:var(--re-data-grid-cell-surface);pointer-events:none}.re-dg-skeleton-row-line{display:block;width:var(--re-data-grid-skeleton-width);height:var(--re-data-grid-skeleton-height);border-radius:var(--re-data-grid-skeleton-rounded);background:linear-gradient(90deg,var(--re-data-grid-skeleton-line) 0%,var(--re-data-grid-skeleton-shine) 50%,var(--re-data-grid-skeleton-line) 100%);background-size:200% 100%;animation:re-dg-skeleton 1.2s ease-in-out infinite}@keyframes re-dg-skeleton{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes re-dg-spinner{to{transform:rotate(360deg)}}.re-dg-scrollbar{position:absolute;right:0;top:0;bottom:0;opacity:0;transition:opacity .15s ease-in-out;pointer-events:none;z-index:4}.re-dg-scrollbar.visible{opacity:1}.re-dg-scrollbar-thumb{position:absolute;right:var(--re-data-grid-scrollbar-offset);width:var(--re-data-grid-scrollbar-thumb-size);border-radius:var(--re-data-grid-scrollbar-thumb-rounded);background:var(--re-data-grid-scrollbar-thumb-color);pointer-events:auto;-webkit-user-select:none;user-select:none}.re-dg-spacer{width:1px}.re-dg-top{top:0}.re-dg-bottom{bottom:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DataGridCellComponent, selector: "re-data-grid-cell", inputs: ["index", "item", "column"] }, { kind: "component", type: SortIcon, selector: "re-sort-ic", inputs: ["direction"] }, { kind: "component", type: ExpandIcon, selector: "re-expand-ic", inputs: ["expanded"] }, { kind: "component", type: CheckboxIcon, selector: "re-checkbox-ic", inputs: ["state", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [CheckboxIcon], () => [SortIcon], () => [ExpandIcon], () => [NgTemplateOutlet], () => [NgTemplateOutlet], () => [DataGridCellComponent], () => [NgTemplateOutlet], () => [NgTemplateOutlet], () => [NgTemplateOutlet]] });
2606
- }
2607
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGrid, decorators: [{
2608
- type: Component,
2609
- args: [{ selector: 're-data-grid', imports: [NgTemplateOutlet, DataGridCellComponent, SortIcon, ExpandIcon, CheckboxIcon], providers: [DataGridVm], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let items = data();\r\n@let empty = !loading() && !items?.length;\r\n@let notEmpty = !!items?.length;\r\n@let skeletonRowsCount = 4;\r\n@let skeletonMode = loadingMode() === 'skeleton';\r\n@let spinnerMode = loadingMode() === 'spinner';\r\n@let showInfinitySkeleton = loading() && skeletonMode && mode() === 'infinity';\r\n@let showPaginationSkeleton = loading() && skeletonMode && mode() === 'pagination' && !notEmpty;\r\n@let showSpinnerLoading = loading() && spinnerMode;\r\n@let extraInfinitySkeletonRows = showInfinitySkeleton ? skeletonRowsCount : 0;\r\n\r\n@let pinnedTopH = vm.pinnedTop().length * rowHeight();\r\n@let pinnedBottomH = vm.pinnedBottom().length * rowHeight();\r\n@let rowH = rowHeight();\r\n@let contentW = vm.contentWidth();\r\n@let cols = vm.columnsToShow();\r\n@let stickyTop = pinnedTopH + headerHeight();\r\n@let normalizedHeaderGroups = vm.normalizedHeaderGroups();\r\n@let stickyRow = stickyRowData();\r\n@let stickyIndex = stickyRowIndex();\r\n\r\n<div\r\n #root\r\n class=\"re-dg-root\"\r\n [class.loading]=\"showSpinnerLoading\"\r\n [class.lock-vertical-scroll]=\"lockVerticalScroll()\"\r\n [style.height]=\"styleHeight()\"\r\n role=\"table\"\r\n>\r\n @if (showSpinnerLoading) {\r\n <div class=\"re-dg-loader\">\r\n @let loadingTemplate = loadingTpl();\r\n\r\n @if (loadingTemplate?.tpl) {\r\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\r\n } @else {\r\n <span class=\"re-dg-loader-spinner\" aria-label=\"Loading\"></span>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n #scroll\r\n class=\"re-dg-body\"\r\n role=\"rowgroup\"\r\n (mouseenter)=\"showScrollbar()\"\r\n (mouseleave)=\"hideScrollbarSoon()\"\r\n >\r\n <ng-template #headerContent>\r\n <div\r\n class=\"re-dg-header\"\r\n role=\"rowgroup\"\r\n [style.width.px]=\"vm.contentWidth()\"\r\n [style.min-width.%]=\"100\"\r\n >\r\n <div #header class=\"re-dg-header-rows\">\r\n @if (normalizedHeaderGroups.length) {\r\n <div class=\"re-dg-row re-dg-header-group-row\" role=\"row\" [style.width.px]=\"vm.contentWidth()\" [style.min-width.%]=\"100\">\r\n @for (group of normalizedHeaderGroups; track group.key) {\r\n @let groupStickyLeft = !!group.startKey && !!group.endKey && vm.isStickyLeft(group.startKey) && vm.isStickyLeft(group.endKey);\r\n @let groupStickyRight = !!group.startKey && !!group.endKey && vm.isStickyRight(group.startKey) && vm.isStickyRight(group.endKey);\r\n\r\n <div\r\n class=\"re-dg-header-cell re-dg-header-group-cell\"\r\n role=\"columnheader\"\r\n [class.sticky-left]=\"groupStickyLeft\"\r\n [class.sticky-right]=\"groupStickyRight\"\r\n [style.left.px]=\"groupStickyLeft && group.startKey ? vm.stickyOffset(group.startKey, 'left') : null\"\r\n [style.right.px]=\"groupStickyRight && group.endKey ? vm.stickyOffset(group.endKey, 'right') : null\"\r\n [style.width.px]=\"group.widthPx\"\r\n [style.justify-content]=\"group.align || 'left'\"\r\n [title]=\"group.title || ''\"\r\n >\r\n @if (group.titleTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"group.titleTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: group.title || '' }\"\r\n />\r\n } @else {\r\n <span class=\"re-dg-header-text\">{{ group.title || '' }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"re-dg-row re-dg-header-row\" role=\"row\" [style.width.px]=\"vm.contentWidth()\" [style.min-width.%]=\"100\">\r\n @for (col of vm.columnsToShow(); track col.key) {\r\n <div\r\n class=\"re-dg-header-cell\"\r\n role=\"columnheader\"\r\n [class.sortable]=\"!!col.sortKey\"\r\n [class.active-sort]=\"currentSortField && (currentSortField === col.sortKey)\"\r\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\r\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\r\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\r\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [style.min-width.px]=\"col.minWidth || null\"\r\n [style.max-width.px]=\"col.maxWidth || null\"\r\n [style.justify-content]=\"col.align || 'left'\"\r\n [attr.aria-sort]=\"ariaSort(col)\"\r\n [attr.tabindex]=\"col.sortKey ? 0 : -1\"\r\n [title]=\"col.header\"\r\n (click)=\"col.sortKey && onSort(col)\"\r\n (keydown.enter)=\"col.sortKey && onSort(col)\"\r\n >\r\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\r\n @let isMultiSelect = selection().mode === 'multi';\r\n\r\n @if (isCheckbox && isMultiSelect) {\r\n @if (deferIcons()) {\r\n @defer (when true) {\r\n <re-checkbox-ic [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\r\n } @placeholder {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n } @loading {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n }\r\n } @else {\r\n <re-checkbox-ic [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\r\n }\r\n } @else {\r\n @if (col.headerTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"col.headerTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: col.header }\"\r\n />\r\n } @else {\r\n <span class=\"re-dg-header-text\">{{ col.header }}</span>\r\n }\r\n }\r\n\r\n @if (col.sortKey) {\r\n <span class=\"re-dg-sort-ind\">\r\n @let direction = currentSortField === col.sortKey ? currentSortOrder : undefined;\r\n\r\n @if (sortTpl()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"sortTpl()!.tpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: direction }\"\r\n />\r\n } @else {\r\n @if (deferIcons()) {\r\n @defer (when true) {\r\n <re-sort-ic [direction]=\"direction\" />\r\n } @placeholder {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n } @loading {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n }\r\n } @else {\r\n <re-sort-ic [direction]=\"direction\" />\r\n }\r\n }\r\n </span>\r\n }\r\n\r\n @if (isExpandable(col)) {\r\n <button (click)=\"$event.stopPropagation(); onExpand(col)\">\r\n @let expanded = expanderMap().get(col.key);\r\n\r\n @if (expanderTpl()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"expanderTpl()!.tpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: expanded }\" />\r\n } @else {\r\n @if (deferIcons()) {\r\n @defer (when true) {\r\n <re-expand-ic [expanded]=\"expanded\" />\r\n } @placeholder {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n } @loading {\r\n <span class=\"re-dg-icon-placeholder\"></span>\r\n }\r\n } @else {\r\n <re-expand-ic [expanded]=\"expanded\" />\r\n }\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- PINNED TOP ROWS -->\r\n @if (notEmpty) {\r\n <ng-template #pinnedTopContent>\r\n @for (pr of vm.pinnedTop(); track trackPinnedRow(pr)) {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-top\" role=\"row\" [style.width.px]=\"contentW\" [style.min-width.%]=\"100\">\r\n @if (pr.rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n } @else {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pinnedRowCells\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n }\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n @if (deferPinned()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"pinnedTopContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-top re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n } @loading {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-top re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"pinnedTopContent\" />\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n\r\n @if (deferHeader()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"headerContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-header re-dg-deferred-placeholder\" [style.min-height.px]=\"headerHeight()\"></div>\r\n } @loading {\r\n <div class=\"re-dg-header re-dg-deferred-placeholder\" [style.min-height.px]=\"headerHeight()\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"headerContent\" />\r\n }\r\n\r\n <ng-template #dataCellContent let-row let-col=\"col\" let-index=\"index\">\r\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\r\n\r\n @if (isCheckbox) {\r\n <re-checkbox-ic [state]=\"selector.isSelected(row)\" />\r\n } @else {\r\n @if (deferCells()) {\r\n @defer (when true) {\r\n <re-data-grid-cell [index]=\"index\" [item]=\"row\" [column]=\"col\" />\r\n } @placeholder {\r\n <span class=\"re-dg-cell-deferred\"></span>\r\n } @loading {\r\n <span class=\"re-dg-cell-deferred\"></span>\r\n }\r\n } @else {\r\n <re-data-grid-cell [index]=\"index\" [item]=\"row\" [column]=\"col\" />\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-template #gridContent>\r\n\r\n <!-- STICKY ROW -->\r\n @if (stickyRow && stickyIndex !== null) {\r\n <div\r\n class=\"re-dg-row re-dg-data-row re-dg-sticky-row\"\r\n role=\"row\"\r\n [style.width.px]=\"vm.contentWidth()\"\r\n [style.min-width.%]=\"100\"\r\n [style.height.px]=\"rowHeight()\"\r\n [style.top.px]=\"stickyRowTopPx()\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"$event.stopPropagation(); rowClick.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n (contextmenu)=\"$event.stopPropagation(); rowContext.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n (dblclick)=\"$event.stopPropagation(); rowDoubleClick.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row: stickyRow, index: stickyIndex, event: $event })\"\r\n >\r\n @let stickyTemplate = stickyRowTpl();\r\n @let rowTemplate = resolveRowTemplate(stickyRow, stickyIndex);\r\n\r\n @if (stickyTemplate?.tpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"stickyTemplate!.tpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: stickyRow, index: stickyIndex }\"\r\n />\r\n } @else if (rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: stickyRow,\r\n index: stickyIndex,\r\n columns: vm.columnsToShow(),\r\n rowHeight: rowHeight(),\r\n isSticky: true\r\n }\"\r\n />\r\n } @else {\r\n @for (col of vm.columnsToShow(); track col.key) {\r\n <div\r\n class=\"re-dg-cell\"\r\n role=\"cell\"\r\n [class.expanded]=\"!!col.expandBy\"\r\n [class]=\"cellClass(col, stickyRow)\"\r\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\r\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\r\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\r\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\r\n [style.justify-items]=\"col.align || 'left'\"\r\n [style.text-align]=\"col.align || 'left'\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [attr.tabindex]=\"0\"\r\n (mouseenter)=\"showTooltip($event, stickyRow, col, stickyIndex)\"\r\n (mouseleave)=\"hideTooltip()\"\r\n (click)=\"onCellClick(stickyRow, col, stickyIndex, $event);\"\r\n (contextmenu)=\"onCellContext(stickyRow, col, stickyIndex, $event)\"\r\n (dblclick)=\"onCellDoubleClick(stickyRow, col, stickyIndex, $event)\"\r\n (keydown.enter)=\"onCellClick(stickyRow, col, stickyIndex, $event)\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"dataCellContent\"\r\n [ngTemplateOutletContext]=\"{ $implicit: stickyRow, col: col, index: stickyIndex }\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n @if (empty) {\r\n @let emptyTemplate = emptyTpl()?.tpl;\r\n\r\n <div class=\"re-dg-empty\">\r\n @if (emptyTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"emptyTemplate\" />\r\n } @else {\r\n <span class=\"re-dg-empty-text\">{{ defaults.translations.emptyState }}</span>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Content -->\r\n @if (notEmpty) {\r\n <div\r\n class=\"re-dg-spacer\"\r\n [style.width.px]=\"contentW\"\r\n [style.height.px]=\"(items.length + extraInfinitySkeletonRows) * rowH - pinnedBottomH\"></div>\r\n\r\n @for (slot of renderSlots(); track slot) {\r\n @let rowIndex = startIndex + slot;\r\n @let row = items[rowIndex];\r\n @let rowTemplate = row ? resolveRowTemplate(row, rowIndex) : null;\r\n\r\n @if (row && !isStickyRowIndex(rowIndex)) {\r\n <div\r\n class=\"re-dg-row re-dg-data-row\"\r\n role=\"row\"\r\n [style.width.px]=\"contentW\"\r\n [style.min-width.%]=\"100\"\r\n [style.height.px]=\"rowH\"\r\n [style.transform]=\"'translateY(' + (rowIndex * rowH + stickyTop) + 'px)'\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"$event.stopPropagation(); rowClick.emit({ row, index: rowIndex, event: $event })\"\r\n (contextmenu)=\"$event.stopPropagation(); rowContext.emit({ row, index: rowIndex, event: $event })\"\r\n (dblclick)=\"$event.stopPropagation(); rowDoubleClick.emit({ row, index: rowIndex, event: $event })\"\r\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row, index: rowIndex, event: $event })\"\r\n >\r\n @if (rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: row,\r\n index: rowIndex,\r\n columns: vm.columnsToShow(),\r\n rowHeight: rowHeight(),\r\n isSticky: false\r\n }\"\r\n />\r\n } @else {\r\n @for (col of cols; track col.key) {\r\n @let stickyLeft = vm.stickyOffset(col.key, 'left');\r\n @let stickyRight = vm.stickyOffset(col.key, 'right');\r\n @let isLeft = vm.isStickyLeft(col.key);\r\n @let isRight = vm.isStickyRight(col.key);\r\n\r\n <div\r\n class=\"re-dg-cell\"\r\n role=\"cell\"\r\n [class.expanded]=\"!!col.expandBy\"\r\n [class]=\"cellClass(col, row)\"\r\n [class.sticky-left]=\"isLeft\"\r\n [class.sticky-right]=\"isRight\"\r\n [style.left.px]=\"stickyLeft\"\r\n [style.right.px]=\"stickyRight\"\r\n [style.justify-items]=\"col.align || 'left'\"\r\n [style.text-align]=\"col.align || 'left'\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [attr.tabindex]=\"0\"\r\n (mouseenter)=\"showTooltip($event, row, col, rowIndex)\"\r\n (mouseleave)=\"hideTooltip()\"\r\n (click)=\"onCellClick(row, col, rowIndex, $event);\"\r\n (contextmenu)=\"onCellContext(row, col, rowIndex, $event)\"\r\n (dblclick)=\"onCellDoubleClick(row, col, rowIndex, $event)\"\r\n (keydown.enter)=\"onCellClick(row, col, rowIndex, $event)\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"dataCellContent\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, col: col, index: rowIndex }\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n\r\n @if (showInfinitySkeleton || showPaginationSkeleton) {\r\n @let loadingTemplate = loadingTpl();\r\n\r\n @if (loadingTemplate?.tpl) {\r\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\r\n } @else {\r\n @for (si of [0, 1, 2, 3]; track si) {\r\n <div\r\n class=\"re-dg-row re-dg-data-row re-dg-skeleton-row\"\r\n role=\"row\"\r\n [style.width.px]=\"contentW\"\r\n [style.min-width.%]=\"100\"\r\n [style.height.px]=\"rowH\"\r\n [style.transform]=\"'translateY(' + (((showInfinitySkeleton ? items.length : 0) + si) * rowH + stickyTop) + 'px)'\"\r\n >\r\n <span class=\"re-dg-skeleton-row-line\"></span>\r\n </div>\r\n }\r\n }\r\n }\r\n\r\n <!-- PINNED BOTTOM ROWS -->\r\n @if (notEmpty) {\r\n <ng-template #pinnedBottomContent>\r\n <div class=\"re-dg-footer\" role=\"rowgroup\">\r\n @for (pr of vm.pinnedBottom(); track trackPinnedRow(pr)) {\r\n <div class=\"re-dg-row re-dg-pinned re-dg-bottom\" role=\"row\" [style.width.px]=\"contentW\" [style.min-width.%]=\"100\">\r\n @if (pr.rowTemplate) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n } @else {\r\n <ng-container\r\n [ngTemplateOutlet]=\"pinnedRowCells\"\r\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\r\n />\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n\r\n @if (deferPinned()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"pinnedBottomContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-footer re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n } @loading {\r\n <div class=\"re-dg-footer re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"pinnedBottomContent\" />\r\n }\r\n }\r\n </ng-template>\r\n\r\n @if (deferContent()) {\r\n @defer (when true) {\r\n <ng-container [ngTemplateOutlet]=\"gridContent\" />\r\n } @placeholder {\r\n <div class=\"re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH * 3\"></div>\r\n } @loading {\r\n <div class=\"re-dg-deferred-placeholder\" [style.min-height.px]=\"rowH * 3\"></div>\r\n }\r\n } @else {\r\n <ng-container [ngTemplateOutlet]=\"gridContent\" />\r\n }\r\n </div>\r\n\r\n <ng-template #pinnedRowCells let-row>\n @for (col of cols; track col.key) {\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n @let isIndex = 'type' in col && col.type === 'index';\n @let stickyLeft = vm.stickyOffset(col.key, 'left');\n @let stickyRight = vm.stickyOffset(col.key, 'right');\n @let isLeft = vm.isStickyLeft(col.key);\n @let isRight = vm.isStickyRight(col.key);\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.expanded]=\"!!col.expandBy\"\n [class]=\"cellClass(col, $any(row))\"\n [class.sticky-left]=\"isLeft\"\n [class.sticky-right]=\"isRight\"\n [style.left.px]=\"stickyLeft\"\n [style.right.px]=\"stickyRight\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.text-align]=\"col.align || 'left'\"\n [style.height.px]=\"rowH\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [attr.tabindex]=\"isCheckbox || isIndex ? -1 : 0\"\n (mouseenter)=\"!isCheckbox && !isIndex && showTooltip($event, $any(row), col, -1)\"\n (mouseleave)=\"!isCheckbox && !isIndex && hideTooltip()\"\n (click)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event);\"\n (contextmenu)=\"!isCheckbox && !isIndex && onCellContext($any(row), col, -1, $event)\"\n (dblclick)=\"!isCheckbox && !isIndex && onCellDoubleClick($any(row), col, -1, $event)\"\n (keydown.enter)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event)\"\n >\n @if (!isCheckbox && !isIndex) {\n <ng-container\n [ngTemplateOutlet]=\"dataCellContent\"\n [ngTemplateOutletContext]=\"{ $implicit: $any(row), col: col, index: -1 }\"\n />\n }\n </div>\n }\n </ng-template>\n\r\n @if (deferTooltip()) {\r\n @defer (when true) {\r\n @let tooltipStateValue = tooltipState();\r\n <div\r\n class=\"re-dg-tooltip\"\r\n #tooltip\r\n [class.visible]=\"tooltipStateValue.visible\"\r\n [style.left.px]=\"tooltipStateValue.x\"\r\n [style.top.px]=\"tooltipStateValue.y\"\r\n >\r\n @if (tooltipStateValue.tpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"tooltipStateValue.tpl\"\r\n [ngTemplateOutletContext]=\"tooltipStateValue.ctx\"\r\n />\r\n } @else {\r\n {{ tooltipStateValue.text }}\r\n }\r\n </div>\r\n }\r\n } @else {\r\n @let tooltipStateValue = tooltipState();\r\n <div\r\n class=\"re-dg-tooltip\"\r\n #tooltip\r\n [class.visible]=\"tooltipStateValue.visible\"\r\n [style.left.px]=\"tooltipStateValue.x\"\r\n [style.top.px]=\"tooltipStateValue.y\"\r\n >\r\n @if (tooltipStateValue.tpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"tooltipStateValue.tpl\"\r\n [ngTemplateOutletContext]=\"tooltipStateValue.ctx\"\r\n />\r\n } @else {\r\n {{ tooltipStateValue.text }}\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Overlay scrollbar -->\r\n <div class=\"re-dg-scrollbar\" [class.visible]=\"vm.scrollbarVisible()\">\r\n <div\r\n class=\"re-dg-scrollbar-thumb\"\r\n role=\"scrollbar\"\r\n aria-orientation=\"vertical\"\r\n aria-hidden=\"false\"\r\n [style.height.px]=\"vm.thumbHeightPx()\"\r\n [style.transform]=\"'translateY(' + vm.thumbTopPx() + 'px)'\"\r\n (mousedown)=\"onThumbDown($event)\"\r\n ></div>\r\n </div>\r\n</div>\r\n", styles: [":host{--re-data-grid-min-height: 200px;--re-data-grid-height: 400px;--re-data-grid-rounded: var(--radius-md, 6px);--re-data-grid-separator-color: var(--border-color);--re-data-grid-separator: 1px solid var(--re-data-grid-separator-color);--re-data-grid-surface: var(--surface-neutral, #fff);--re-data-grid-active: var(--primary-color, #2a90f4);--re-data-grid-empty-color: #777;--re-data-grid-empty-surface: transparent;--re-data-grid-loading-color: #444;--re-data-grid-loading-surface: rgba(255, 255, 255, .5);--re-data-grid-spinner-size: 2rem;--re-data-grid-spinner-width: .25rem;--re-data-grid-spinner-track-color: rgba(0, 0, 0, .12);--re-data-grid-skeleton-width: 100%;--re-data-grid-skeleton-height: 100%;--re-data-grid-skeleton-rounded: var(--re-data-grid-rounded, .75rem);--re-data-grid-skeleton-shine: rgba(255, 255, 255, .8);--re-data-grid-skeleton-line: #e7ebf0;--re-data-grid-scrollbar-size: 4px;--re-data-grid-scrollbar-offset: 2px;--re-data-grid-scrollbar-track-rounded: .25rem;--re-data-grid-scrollbar-track-surface: transparent;--re-data-grid-scrollbar-thumb-size: 8px;--re-data-grid-scrollbar-thumb-color: rgba(0, 0, 0, .25);--re-data-grid-scrollbar-thumb-active-color: rgba(0, 0, 0, .45);--re-data-grid-scrollbar-thumb-rounded: var(--re-data-grid-scrollbar-track-rounded);--re-data-grid-tooltip-surface: #0f172a;--re-data-grid-tooltip-color: #f8fafc;--re-data-grid-tooltip-radius: .5rem;--re-data-grid-tooltip-padding: .4rem .6rem;--re-data-grid-tooltip-shadow: 0 8px 24px rgba(15, 23, 42, .25);--re-data-grid-tooltip-z: 60;--re-data-grid-header-rounded: var(--re-data-grid-rounded);--re-data-grid-header-surface: #fff;--re-data-grid-header-body-gap: 0px;--re-data-grid-header-row-height: 40px;--re-data-grid-header-row-separator-color: #ccc;--re-data-grid-header-row-separator: 1px solid var(--re-data-grid-header-row-separator-color);--re-data-grid-header-group-row-height: var(--re-data-grid-header-row-height);--re-data-grid-header-group-row-separator-color: var(--re-data-grid-header-row-separator-color);--re-data-grid-header-group-row-separator: 1px solid var(--re-data-grid-header-group-row-separator-color);--re-data-grid-header-group-cell-font-weight: var(--re-data-grid-header-cell-font-weight);--re-data-grid-header-group-cell-font-size: var(--re-data-grid-header-cell-font-size);--re-data-grid-header-group-cell-color: var(--re-data-grid-header-cell-color);--re-data-grid-header-group-cell-surface: var(--re-data-grid-header-cell-surface);--re-data-grid-header-cell-font-weight: 600;--re-data-grid-header-cell-font-size: .8rem;--re-data-grid-header-cell-color: #000;--re-data-grid-header-cell-surface: #fafafa;--re-data-grid-footer-separator-color: #ccc;--re-data-grid-footer-separator: 1px solid var(--re-data-grid-footer-separator-color);--re-data-grid-footer-surface: #fff;--re-data-grid-row-separator-color: #bbb;--re-data-grid-row-separator: 1px solid var(--re-data-grid-row-separator-color);--re-data-grid-row-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-row-hover-surface: var(--re-data-grid-cell-surface);--re-data-grid-row-hover-color: var(--re-data-grid-cell-color);--re-data-grid-row-hover-rounded: 0px;--re-data-grid-column-separator-color: transparent;--re-data-grid-column-separator: 1px solid var(--re-data-grid-column-separator-color);--re-data-grid-column-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-cell-paddings: .4rem .625rem;--re-data-grid-cell-font-weight: 400;--re-data-grid-cell-font-size: .75rem;--re-data-grid-cell-color: #000;--re-data-grid-cell-surface: #fff;--re-data-grid-sticky-header-cell-surface: #fff;--re-data-grid-sticky-cell-surface: #fdfdfd;--re-data-grid-sticky-cell-row-odd-surface: #fdfdfd;--re-data-grid-sticky-cell-left-shadow: 2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-sticky-cell-right-shadow: -2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-pinned-surface: #fcfcfc;--re-data-grid-pinned-separator-color: #eee;--re-data-grid-pinned-separator: 1px solid var(--re-data-grid-pinned-separator-color);--re-data-grid-expander-color: var(--primary-color, currentColor);--re-data-grid-expanded-color: var(--re-data-grid-cell-color, #000);--re-data-grid-expanded-surface: var(--re-data-grid-cell-surface, #fff);display:block;min-height:0;min-width:0}:host,:host *,:host *:before,:host *:after{box-sizing:border-box;outline:none}:host button{outline:none}.re-dg-root{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;min-height:var(--re-data-grid-min-height);border-radius:var(--re-data-grid-rounded);border:var(--re-data-grid-separator)}.re-dg-root.fill{display:block}.re-dg-root.loading{pointer-events:none;-webkit-user-select:none;user-select:none;cursor:wait}.re-dg-root.loading .re-dg-body{overflow:hidden}.re-dg-root.loading .re-dg-scrollbar{display:none!important}.re-dg-root.loading .re-dg-loader{pointer-events:all}.re-dg-root.lock-vertical-scroll .re-dg-body{overflow-x:auto;overflow-y:hidden}.re-dg-root.lock-vertical-scroll .re-dg-scrollbar{display:none!important}.re-dg-body{position:relative;flex:1 1 auto;min-height:0;min-width:0;height:inherit;border:var(--re-data-grid-separator);border-radius:var(--re-data-grid-rounded);background-color:var(--re-data-grid-surface);overflow:auto;scrollbar-width:auto;-ms-overflow-style:auto}.re-dg-body::-webkit-scrollbar{width:var(--re-data-grid-scrollbar-size);height:var(--re-data-grid-scrollbar-size)}.re-dg-body::-webkit-scrollbar:vertical{width:0}.re-dg-body::-webkit-scrollbar-track{border-radius:var(--re-data-grid-scrollbar-track-rounded);background:var(--re-data-grid-scrollbar-track-surface)}.re-dg-body::-webkit-scrollbar-thumb{border-radius:var(--re-data-grid-scrollbar-thumb-rounded);background:var(--re-data-grid-scrollbar-thumb-color);transition:opacity .3s ease}.re-dg-body::-webkit-scrollbar-thumb:hover{background:var(--re-data-grid-scrollbar-thumb-active-color)}.re-dg-header,.re-dg-footer{position:sticky;z-index:3}.re-dg-header{top:0;background-color:var(--re-data-grid-header-surface)}.re-dg-header-row{min-height:var(--re-data-grid-header-row-height)}.re-dg-header-group-row{min-height:var(--re-data-grid-header-group-row-height)}.re-dg-header-rows{display:flex;flex-direction:column;padding-bottom:var(--re-data-grid-header-body-gap)}.re-dg-footer{bottom:0;border-radius:0 0 var(--re-data-grid-rounded) var(--re-data-grid-rounded);background-color:var(--re-data-grid-footer-surface)}.re-dg-row{position:relative;display:flex}.re-dg-data-row{position:absolute;left:0;top:0;min-width:100%;cursor:default;will-change:transform}.re-dg-sticky-row{z-index:2;top:0}.re-dg-cell,.re-dg-header-cell{display:flex;flex:0 0 auto;align-items:center;padding:var(--re-data-grid-cell-paddings);border-right:var(--re-data-grid-column-separator);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.re-dg-cell{width:100%;border-bottom:var(--re-data-grid-row-separator);font-weight:var(--re-data-grid-cell-font-weight);font-size:var(--re-data-grid-cell-font-size);color:var(--re-data-grid-cell-color);background-color:var(--re-data-grid-cell-surface)}.re-dg-row:nth-child(odd) .re-dg-cell{background-color:var(--re-data-grid-row-odd-surface)}.re-dg-row:nth-child(odd) .re-dg-cell.sticky-left,.re-dg-row:nth-child(odd) .re-dg-cell.sticky-right{background-color:var(--re-data-grid-sticky-cell-row-odd-surface)}.re-dg-cell:nth-child(odd){background-color:var(--re-data-grid-column-odd-surface)}.re-dg-bottom>.re-dg-cell{border-top:var(--re-data-grid-footer-separator)}.re-dg-header-cell{align-items:center;gap:.75rem;border-bottom:var(--re-data-grid-header-row-separator);font-weight:var(--re-data-grid-header-cell-font-weight);font-size:var(--re-data-grid-header-cell-font-size);color:var(--re-data-grid-header-cell-color);background:var(--re-data-grid-header-cell-surface);-webkit-user-select:none;user-select:none;transition:color .3s ease-in-out}.re-dg-header-cell.re-dg-header-group-cell{border-bottom:var(--re-data-grid-header-group-row-separator);font-weight:var(--re-data-grid-header-group-cell-font-weight);font-size:var(--re-data-grid-header-group-cell-font-size);color:var(--re-data-grid-header-group-cell-color);background:var(--re-data-grid-header-group-cell-surface)}.re-dg-header-rows>.re-dg-row:first-child .re-dg-header-cell:first-child{border-radius:var(--re-data-grid-header-rounded) 0 0 0}.re-dg-header-rows>.re-dg-row:first-child .re-dg-header-cell:last-child{border-radius:0 var(--re-data-grid-header-rounded) 0 0}.re-dg-data-row:last-child .re-dg-cell:first-child{border-radius:0 0 0 var(--re-data-grid-rounded)}.re-dg-data-row:last-child .re-dg-cell:last-child{border-radius:0 0 var(--re-data-grid-rounded) 0}.re-dg-header-cell .re-dg-header-text{display:-webkit-box;max-height:2.4em;line-height:1.2;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.re-dg-row.re-dg-pinned>.re-dg-cell{border-bottom:var(--re-data-grid-pinned-separator);background-color:var(--re-data-grid-pinned-surface)}.re-dg-row .re-dg-header-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row .re-dg-header-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row.re-dg-pinned>.re-dg-cell.sticky-left,.re-dg-row.re-dg-pinned>.re-dg-cell.sticky-right{background-color:var(--re-data-grid-pinned-surface)}.re-dg-row:hover>.re-dg-cell,.re-dg-row:hover>.re-dg-cell.sticky-left,.re-dg-row:hover>.re-dg-cell.sticky-right{background-color:var(--re-data-grid-row-hover-surface)!important;color:var(--re-data-grid-row-hover-color)!important}.re-dg-row:hover>.re-dg-cell:first-child{border-radius:var(--re-data-grid-row-hover-rounded) 0 0 var(--re-data-grid-row-hover-rounded)}.re-dg-row:hover>.re-dg-cell:last-child{border-radius:0 var(--re-data-grid-row-hover-rounded) var(--re-data-grid-row-hover-rounded) 0}.sticky-left,.sticky-right{position:sticky;z-index:2}.sortable{cursor:pointer}.active-sort{color:var(--re-data-grid-active)}.re-dg-sort-ind{margin-left:6px}.re-dg-icon-placeholder{display:inline-block;width:1rem;height:1rem}.re-dg-cell-deferred{display:block;width:100%;height:100%}.re-dg-deferred-placeholder{background:transparent}.re-dg-data-row .re-dg-cell.expanded{color:var(--re-data-grid-expanded-color);background:var(--re-data-grid-expanded-surface)}.re-dg-empty{position:absolute;inset:0;display:grid;place-items:center;height:inherit;width:100%;border-radius:var(--re-data-grid-rounded);color:var(--re-data-grid-empty-color);background:var(--re-data-grid-empty-surface)}.re-dg-empty-text{width:100%;text-align:center}.re-dg-loader{position:absolute;inset:0;display:grid;place-items:center;height:inherit;border-radius:var(--re-data-grid-rounded);background-color:var(--re-data-grid-loading-surface);color:var(--re-data-grid-loading-color);z-index:5}.re-dg-tooltip{position:fixed;left:0;top:0;max-width:min(28rem,70vw);padding:var(--re-data-grid-tooltip-padding);border-radius:var(--re-data-grid-tooltip-radius);background:var(--re-data-grid-tooltip-surface);color:var(--re-data-grid-tooltip-color);box-shadow:var(--re-data-grid-tooltip-shadow);font-size:.75rem;line-height:1.2;z-index:var(--re-data-grid-tooltip-z);pointer-events:none;opacity:0;transform:translateY(4px);transition:opacity .12s ease,transform .12s ease}.re-dg-tooltip.visible{opacity:1;transform:translateY(0)}.re-dg-loader-spinner{width:var(--re-data-grid-spinner-size);height:var(--re-data-grid-spinner-size);border-radius:50%;border:var(--re-data-grid-spinner-width) solid var(--re-data-grid-spinner-track-color);border-top-color:var(--re-data-grid-loading-color);animation:re-dg-spinner .8s linear infinite}.re-dg-skeleton-row{display:flex;align-items:center;padding:var(--re-data-grid-cell-paddings);border-bottom:var(--re-data-grid-row-separator);background-color:var(--re-data-grid-cell-surface);pointer-events:none}.re-dg-skeleton-row-line{display:block;width:var(--re-data-grid-skeleton-width);height:var(--re-data-grid-skeleton-height);border-radius:var(--re-data-grid-skeleton-rounded);background:linear-gradient(90deg,var(--re-data-grid-skeleton-line) 0%,var(--re-data-grid-skeleton-shine) 50%,var(--re-data-grid-skeleton-line) 100%);background-size:200% 100%;animation:re-dg-skeleton 1.2s ease-in-out infinite}@keyframes re-dg-skeleton{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes re-dg-spinner{to{transform:rotate(360deg)}}.re-dg-scrollbar{position:absolute;right:0;top:0;bottom:0;opacity:0;transition:opacity .15s ease-in-out;pointer-events:none;z-index:4}.re-dg-scrollbar.visible{opacity:1}.re-dg-scrollbar-thumb{position:absolute;right:var(--re-data-grid-scrollbar-offset);width:var(--re-data-grid-scrollbar-thumb-size);border-radius:var(--re-data-grid-scrollbar-thumb-rounded);background:var(--re-data-grid-scrollbar-thumb-color);pointer-events:auto;-webkit-user-select:none;user-select:none}.re-dg-spacer{width:1px}.re-dg-top{top:0}.re-dg-bottom{bottom:0}\n"] }]
2610
- }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], pinnedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinnedRows", required: false }] }], isRowSticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "isRowSticky", required: false }] }], getRowTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "getRowTemplate", required: false }] }], hasIndexColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasIndexColumn", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], virtualBuffer: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualBuffer", required: false }] }], lockVerticalScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockVerticalScroll", required: false }] }], headerGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerGroups", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingMode", required: false }] }], deferContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "deferContent", required: false }] }], deferHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "deferHeader", required: false }] }], deferPinned: [{ type: i0.Input, args: [{ isSignal: true, alias: "deferPinned", required: false }] }], deferCells: [{ type: i0.Input, args: [{ isSignal: true, alias: "deferCells", required: false }] }], deferIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "deferIcons", required: false }] }], deferTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "deferTooltip", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], pageStartFromZero: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageStartFromZero", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], selectChange: [{ type: i0.Output, args: ["selectChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], rowContext: [{ type: i0.Output, args: ["rowContext"] }], rowDoubleClick: [{ type: i0.Output, args: ["rowDoubleClick"] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], cellContext: [{ type: i0.Output, args: ["cellContext"] }], cellDoubleClick: [{ type: i0.Output, args: ["cellDoubleClick"] }], rootEl: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }], scrollEl: [{ type: i0.ViewChild, args: ['scroll', { isSignal: true }] }], headerEl: [{ type: i0.ViewChild, args: ['header', { isSignal: true }] }], cellTypedSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridTypeCellTemplateDirective), { isSignal: true }] }], cellDataSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridCellTemplateDirective), { isSignal: true }] }], declarativeColumnRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridDeclarativeColumn), { isSignal: true }] }], headerSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridHeaderTemplateDirective), { isSignal: true }] }], emptySlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridCellEmptyDirective), { isSignal: true }] }], loadingSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridCellLoadingDirective), { isSignal: true }] }], sortIcSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridSortIconDirective), { isSignal: true }] }], expanderIcSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridExpanderIconDirective), { isSignal: true }] }], stickyRowSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridStickyRowDirective), { isSignal: true }] }], rowSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridRowDirective), { isSignal: true }] }], tooltipEl: [{ type: i0.ViewChild, args: ['tooltip', { isSignal: true }] }] } });
2611
-
2612
- /**
2613
- * Generated bundle index. Do not edit.
2614
- */
2615
-
2616
- export { DATA_GRID_CONFIG, DEFAULT_DATA_GRID_DEFAULTS, DataGrid, DataGridCellEmptyDirective, DataGridCellLoadingDirective, DataGridCellTemplateDirective, DataGridDeclarativeCellDirective, DataGridDeclarativeColumn, DataGridDeclarativeHeaderDirective, DataGridExpanderIconDirective, DataGridHeaderTemplateDirective, DataGridRowDirective, DataGridSortIconDirective, DataGridStickyRowDirective, DataGridTypeCellTemplateDirective, provideDataGridDefaults };
1
+ export { o as DATA_GRID_CONFIG, p as DEFAULT_DATA_GRID_DEFAULTS, r as DataGrid, i as DataGridCellEmptyDirective, j as DataGridCellLoadingDirective, b as DataGridCellTemplateDirective, h as DataGridDeclarativeCellDirective, f as DataGridDeclarativeColumn, g as DataGridDeclarativeHeaderDirective, n as DataGridExpanderIconDirective, d as DataGridHeaderTemplateDirective, e as DataGridRowDirective, l as DataGridSortIconDirective, k as DataGridStickyRowDirective, D as DataGridTypeCellTemplateDirective, q as provideDataGridDefaults } from './reforgium-data-grid-reforgium-data-grid-Dn9s4YO5.mjs';
2617
2
  //# sourceMappingURL=reforgium-data-grid.mjs.map