@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.
@@ -0,0 +1,3274 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, inject, TemplateRef, Directive, booleanAttribute, contentChild, Component, numberAttribute, InjectionToken, makeEnvironmentProviders, signal, computed, effect, Injectable, ChangeDetectionStrategy, output, untracked, DestroyRef, afterRenderEffect, viewChild, NgZone, contentChildren } from '@angular/core';
3
+ import { NgTemplateOutlet, DatePipe, DecimalPipe } from '@angular/common';
4
+ import { Subject, debounceTime, fromEvent, Subscription } 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
+ sortMode: 'single',
313
+ rowHeight: 40,
314
+ headerHeight: 48,
315
+ height: 'default',
316
+ virtualBuffer: 8,
317
+ loadingMode: 'spinner',
318
+ pageStartFromZero: true,
319
+ deferContent: true,
320
+ deferHeader: false,
321
+ deferPinned: false,
322
+ deferCells: false,
323
+ deferIcons: true,
324
+ deferTooltip: false,
325
+ translations: {
326
+ emptyState: 'No records found',
327
+ itemsPerPageLabel: 'Items per page:',
328
+ nextPageLabel: 'Next page',
329
+ prevPageLabel: 'Previous page',
330
+ },
331
+ debounce: {
332
+ resize: 100,
333
+ scroll: 50,
334
+ },
335
+ };
336
+ const DATA_GRID_CONFIG = new InjectionToken('RE_DATA_GRID_DEFAULTS', {
337
+ providedIn: 'root',
338
+ factory: () => DEFAULT_DATA_GRID_DEFAULTS,
339
+ });
340
+ /**
341
+ * Provides default configuration for Data Grid, overriding base settings.
342
+ *
343
+ * @param config Partial configuration object to be merged with current settings.
344
+ * @returns EnvironmentProviders for use in application or component configuration.
345
+ */
346
+ function provideDataGridDefaults(config) {
347
+ return makeEnvironmentProviders([
348
+ {
349
+ provide: DATA_GRID_CONFIG,
350
+ useFactory: () => {
351
+ const parent = inject(DATA_GRID_CONFIG, { optional: true, skipSelf: true });
352
+ const base = parent ?? DEFAULT_DATA_GRID_DEFAULTS;
353
+ return {
354
+ ...base,
355
+ ...config,
356
+ selection: config.selection ?? base.selection,
357
+ translations: { ...base.translations, ...config.translations },
358
+ debounce: { ...base.debounce, ...config.debounce },
359
+ };
360
+ },
361
+ },
362
+ ]);
363
+ }
364
+
365
+ const GRID_INDEX_COLUMN = {
366
+ key: '_index',
367
+ type: 'index',
368
+ align: 'center',
369
+ header: '№',
370
+ width: 72,
371
+ sticky: 'left',
372
+ };
373
+ const GRID_CHECKBOX_COLUMN = {
374
+ key: '_checkbox',
375
+ type: 'checkbox',
376
+ align: 'center',
377
+ header: 'checkbox',
378
+ width: 44,
379
+ sticky: 'left',
380
+ };
381
+
382
+ /**
383
+ * Calculates and distributes column widths within a container based on column configuration.
384
+ *
385
+ * The function implements a flexible layout algorithm that:
386
+ * - Respects fixed-width columns (with `width` property set)
387
+ * - Distributes remaining space among auto-sized columns based on their `flex` ratios
388
+ * - Enforces `minWidth` and `maxWidth` constraints
389
+ * - Uses a "water-fill" algorithm to grow columns proportionally
390
+ * - Handles rounding errors to ensure total width matches container width
391
+ *
392
+ * @param columns - Array of column configuration objects with properties
393
+ * like `visible`, `width`, `minWidth`, `maxWidth`, `flex`, and `key`
394
+ * @param containerWidth - Available width in pixels for all columns
395
+ * @param defaultCol - Default minimum width for auto-sized columns without explicit `minWidth`
396
+ * @returns Layout result containing computed widths array, total width, and width lookup by column key
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * const result = layoutColumns(
401
+ * [
402
+ * { key: 'id', width: 50, visible: true },
403
+ * { key: 'name', minWidth: 100, flex: 2, visible: true },
404
+ * { key: 'age', minWidth: 80, flex: 1, visible: true }
405
+ * ],
406
+ * 800,
407
+ * 100
408
+ * );
409
+ * // result.widths = [50, 500, 250]
410
+ * // result.total = 800
411
+ * // result.byKey = { id: 50, name: 500, age: 250 }
412
+ * ```
413
+ */
414
+ function layoutColumns(columns, containerWidth, defaultCol) {
415
+ const idx = visibleIndexes(columns);
416
+ const { fixedIdx, autoIdx } = splitFixed(columns, idx);
417
+ const fixedWidths = computeFixedWidths(columns, fixedIdx);
418
+ const baseAuto = computeBaseAuto(columns, autoIdx, defaultCol);
419
+ const sumFixed = sum(fixedWidths);
420
+ const sumBase = sum(baseAuto.map((w) => w.width));
421
+ const free = Math.max(containerWidth - sumFixed - sumBase, 0);
422
+ const grownAuto = distributeFree(columns, baseAuto, free); // water-fill
423
+ const widths = new Array(columns.length).fill(0);
424
+ if (containerWidth <= 0) {
425
+ const byKey = {};
426
+ for (let i = 0; i < columns.length; i++) {
427
+ // noinspection PointlessBooleanExpressionJS
428
+ columns[i].visible !== false && (byKey[columns[i].key] = 0);
429
+ }
430
+ return { widths, total: 0, byKey };
431
+ }
432
+ for (const { index, width } of fixedWidths) {
433
+ widths[index] = width;
434
+ }
435
+ for (const { index, width } of grownAuto) {
436
+ widths[index] = width;
437
+ }
438
+ roundAndFix(columns, widths, fixedIdx, autoIdx, containerWidth);
439
+ let total = 0;
440
+ const byKey = {};
441
+ for (const i of idx) {
442
+ total += widths[i];
443
+ byKey[columns[i].key] = widths[i];
444
+ }
445
+ return { widths, total, byKey };
446
+ }
447
+ /**
448
+ * Filters and returns indexes of visible columns.
449
+ *
450
+ * A column is considered visible if its `visible` property is not explicitly set to `false`.
451
+ *
452
+ * @param cols - Array of column configurations
453
+ * @returns Array of indexes for columns that should be displayed
454
+ */
455
+ function visibleIndexes(cols) {
456
+ const out = [];
457
+ for (let i = 0; i < cols.length; i++) {
458
+ // noinspection PointlessBooleanExpressionJS
459
+ cols[i].visible !== false && out.push(i);
460
+ }
461
+ return out;
462
+ }
463
+ /**
464
+ * Splits visible column indexes into fixed-width and auto-sized groups.
465
+ *
466
+ * Fixed columns have an explicit `width` property defined.
467
+ * Auto-sized columns have `width` as `undefined` and will grow to fill available space.
468
+ *
469
+ * @param cols - Array of column configurations
470
+ * @param visibleIdx - Array of visible column indexes
471
+ * @returns Object with `fixedIdx` (fixed-width column indexes) and `autoIdx` (auto-sized column indexes)
472
+ */
473
+ function splitFixed(cols, visibleIdx) {
474
+ const fixedIdx = [];
475
+ const autoIdx = [];
476
+ for (const i of visibleIdx) {
477
+ cols[i].width === undefined ? autoIdx.push(i) : fixedIdx.push(i);
478
+ }
479
+ return { fixedIdx, autoIdx };
480
+ }
481
+ /**
482
+ * Computes actual widths for fixed-width columns, respecting min/max constraints.
483
+ *
484
+ * Takes the explicit `width` value and clamps it between `minWidth` and `maxWidth`.
485
+ *
486
+ * @param cols - Array of column configurations
487
+ * @param fixedIdx - Array of fixed-width column indexes
488
+ * @returns Array of objects with column index and computed width
489
+ */
490
+ const computeFixedWidths = (cols, fixedIdx) => fixedIdx.map((index) => {
491
+ const col = cols[index];
492
+ const width = clamp$1(col.width, col.minWidth, col.maxWidth);
493
+ return { index, width };
494
+ });
495
+ /**
496
+ * Computes base (minimum) widths for auto-sized columns before distribution of free space.
497
+ *
498
+ * Uses column's `minWidth` if specified, otherwise falls back to the default value.
499
+ * The base width is clamped between `minWidth` and `maxWidth` constraints.
500
+ *
501
+ * @param cols - Array of column configurations
502
+ * @param autoIdx - Array of auto-sized column indexes
503
+ * @param def - Default minimum width to use when column's `minWidth` is not specified
504
+ * @returns Array of objects with column index and base width
505
+ */
506
+ const computeBaseAuto = (cols, autoIdx, def) => autoIdx.map((index) => {
507
+ const c = cols[index];
508
+ const base = clamp$1(c.minWidth ?? def, c.minWidth, c.maxWidth);
509
+ return { index, width: base };
510
+ });
511
+ /**
512
+ * Distributes free space among auto-sized columns using a "water-fill" algorithm.
513
+ *
514
+ * The algorithm works iteratively:
515
+ * 1. Identifies columns that can still grow (haven't reached `maxWidth`)
516
+ * 2. Distributes remaining space proportionally based on each column's `flex` ratio
517
+ * 3. Respects `maxWidth` constraints by capping growth
518
+ * 4. Repeats until no space remains or no columns can grow further
519
+ *
520
+ * This ensures that columns with higher `flex` values receive proportionally more space,
521
+ * while respecting all width constraints.
522
+ *
523
+ * @param cols - Array of column configurations
524
+ * @param base - Array of column indexes with their base widths before distribution
525
+ * @param free - Amount of free space (in pixels) to distribute among columns
526
+ * @returns Array of objects with column index and final width after distribution
527
+ */
528
+ function distributeFree(cols, base, free) {
529
+ if (free <= 0 || base.length === 0) {
530
+ return base;
531
+ }
532
+ const widths = base.map((b) => ({ ...b }));
533
+ let remaining = free;
534
+ let growable = widths.filter((w) => widthsCanGrow(cols, w.index, w.width)).map((w) => w.index);
535
+ while (remaining > 0 && growable.length > 0) {
536
+ const flexSum = growable.reduce((s, i) => s + (cols[i].flex ?? 1), 0) || 1;
537
+ let distributed = 0;
538
+ for (const i of growable) {
539
+ const rec = widths.find((w) => w.index === i);
540
+ const cap = (cols[i].maxWidth ?? Infinity) - rec.width;
541
+ if (cap <= 0) {
542
+ continue;
543
+ }
544
+ const ideal = remaining * ((cols[i].flex ?? 1) / flexSum);
545
+ const add = ideal < cap ? ideal : cap;
546
+ if (add > 0) {
547
+ rec.width += add;
548
+ distributed += add;
549
+ }
550
+ }
551
+ if (distributed <= 1e-6) {
552
+ break;
553
+ }
554
+ remaining -= distributed;
555
+ growable = widths.filter((w) => widthsCanGrow(cols, w.index, w.width)).map((w) => w.index);
556
+ }
557
+ return widths;
558
+ }
559
+ /**
560
+ * Checks whether a column can grow beyond its current width.
561
+ *
562
+ * A column can grow if its current width is less than its `maxWidth` constraint
563
+ * (or `Infinity` if no max is specified), with a small epsilon tolerance.
564
+ *
565
+ * @param cols - Array of column configurations
566
+ * @param i - Column index to check
567
+ * @param cur - Current width of the column
568
+ * @returns `true` if the column can grow, `false` otherwise
569
+ */
570
+ function widthsCanGrow(cols, i, cur) {
571
+ const max = cols[i].maxWidth ?? Infinity;
572
+ return cur < max - 1e-6;
573
+ }
574
+ /**
575
+ * Rounds auto-sized column widths to integers and distributes any remaining pixels to match container width exactly.
576
+ *
577
+ * This function handles rounding errors that occur when distributing fractional widths:
578
+ * 1. Floors all auto-sized column widths to integers
579
+ * 2. Calculates how many pixels are needed to reach the exact container width
580
+ * 3. Distributes remaining pixels one-by-one to columns (right-to-left) that haven't reached their `maxWidth`
581
+ *
582
+ * Fixed-width columns are not modified. This ensures the total width matches the container precisely.
583
+ *
584
+ * @param cols - Array of column configurations
585
+ * @param widths - Array of column widths to be modified in place
586
+ * @param fixedIdx - Array of fixed-width column indexes (not modified)
587
+ * @param autoIdx - Array of auto-sized column indexes (will be rounded and adjusted)
588
+ * @param containerWidth - Target total width that must be matched exactly
589
+ */
590
+ function roundAndFix(cols, widths, fixedIdx, autoIdx, containerWidth) {
591
+ const sumFixed = fixedIdx.reduce((s, i) => s + widths[i], 0);
592
+ let sumAuto = 0;
593
+ for (const i of autoIdx) {
594
+ widths[i] = Math.floor(widths[i]);
595
+ sumAuto += widths[i];
596
+ }
597
+ let need = Math.round(Math.max(containerWidth - sumFixed - sumAuto, 0));
598
+ if (need === 0) {
599
+ return;
600
+ }
601
+ for (let k = autoIdx.length - 1; k >= 0 && need > 0; k--) {
602
+ const i = autoIdx[k];
603
+ const max = cols[i].maxWidth ?? Infinity;
604
+ if (widths[i] + 1 <= max) {
605
+ widths[i] += 1;
606
+ need--;
607
+ }
608
+ }
609
+ }
610
+ /**
611
+ * Clamps a numeric value between optional minimum and maximum bounds.
612
+ *
613
+ * If `min` is provided and the value is less than it, returns `min`.
614
+ * If `max` is provided and the value is greater than it, returns `max`.
615
+ * Otherwise, returns the original value.
616
+ *
617
+ * @param v - Value to clamp
618
+ * @param min - Optional minimum bound
619
+ * @param max - Optional maximum bound
620
+ * @returns Clamped value
621
+ */
622
+ function clamp$1(v, min, max) {
623
+ min != null && v < min && (v = min);
624
+ max != null && v > max && (v = max);
625
+ return v;
626
+ }
627
+ /**
628
+ * Calculates the sum of numeric values or width properties in an array.
629
+ *
630
+ * Supports two input formats:
631
+ * - Array of numbers: sums all numeric values
632
+ * - Array of objects with `width` property: sums all `width` values
633
+ *
634
+ * @param items - Array of numbers or objects with `width` property
635
+ * @returns Sum of all values
636
+ */
637
+ function sum(items) {
638
+ if (Array.isArray(items) && typeof items[0] === 'number') {
639
+ return items.reduce((s, x) => s + x, 0);
640
+ }
641
+ return items.reduce((s, x) => s + x.width, 0);
642
+ }
643
+
644
+ // noinspection ES6PreferShortImport
645
+ const DEFAULT_COLUMN_WIDTH = 140;
646
+ /**
647
+ * Computes and normalizes header groups based on the provided headers and columns.
648
+ *
649
+ * @param {GridHeaderGroup<Data>[]} headers - An array of header group objects representing the grouping information
650
+ * for the grid.
651
+ * @param {GridColumn<Data>[]} columns - An array of column definitions describing the columns in the grid.
652
+ * @return {NormalizedHeader[]} An array of normalized header objects, where each object contains information about
653
+ * the computed header ranges, widths, and keys.
654
+ */
655
+ function computeHeaderGroups(headers = [], columns = []) {
656
+ if (!columns.length || !headers.length) {
657
+ return [];
658
+ }
659
+ const keyToIndex = new Map(columns.map((col, index) => [col.key, index]));
660
+ const columnWidths = columns.map(resolveColumnWidth);
661
+ const prefix = buildWidthesPrefixSums(columnWidths);
662
+ const ranges = [];
663
+ const occupied = new Set();
664
+ for (const header of headers) {
665
+ const start = keyToIndex.get(header.from);
666
+ const resolvedTo = header.to ?? header.from;
667
+ const end = keyToIndex.get(resolvedTo);
668
+ if (start === undefined || end === undefined) {
669
+ continue;
670
+ }
671
+ const rangeStart = Math.min(start, end);
672
+ const rangeEnd = Math.max(start, end);
673
+ if (hasOverlap(rangeStart, rangeEnd, occupied)) {
674
+ continue;
675
+ }
676
+ for (let i = rangeStart; i <= rangeEnd; i++) {
677
+ occupied.add(i);
678
+ }
679
+ ranges.push({ header, start: rangeStart, end: rangeEnd });
680
+ }
681
+ const rangesByStart = new Map(ranges.map((range) => [range.start, range]));
682
+ const normalized = [];
683
+ for (let index = 0; index < columns.length;) {
684
+ const range = rangesByStart.get(index);
685
+ if (range) {
686
+ normalized.push(normalizeRange(range, prefix, columns));
687
+ index = range.end + 1;
688
+ continue;
689
+ }
690
+ const start = index;
691
+ while (index < columns.length && !rangesByStart.has(index)) {
692
+ index++;
693
+ }
694
+ const end = index - 1;
695
+ normalized.push({
696
+ key: `_rest_${columns[start].key}_${columns[end].key}`,
697
+ widthPx: sumByRange(prefix, start, end),
698
+ startKey: columns[start]?.key,
699
+ endKey: columns[end]?.key,
700
+ });
701
+ }
702
+ return normalized;
703
+ }
704
+ function normalizeRange(range, prefix, columns) {
705
+ const base = {
706
+ key: range.header.key,
707
+ widthPx: sumByRange(prefix, range.start, range.end),
708
+ startKey: columns[range.start]?.key,
709
+ endKey: columns[range.end]?.key,
710
+ };
711
+ if ('titleTemplate' in range.header) {
712
+ base.titleTemplate = range.header.titleTemplate;
713
+ return base;
714
+ }
715
+ base.title = range.header.title;
716
+ base.align = range.header.align;
717
+ return base;
718
+ }
719
+ function resolveColumnWidth(column) {
720
+ const width = asFiniteNumber(column.width);
721
+ const minWidth = asFiniteNumber(column.minWidth);
722
+ const maxWidth = asFiniteNumber(column.maxWidth);
723
+ let result = width ?? minWidth ?? DEFAULT_COLUMN_WIDTH;
724
+ if (minWidth !== null && result < minWidth) {
725
+ result = minWidth;
726
+ }
727
+ if (maxWidth !== null && result > maxWidth) {
728
+ result = maxWidth;
729
+ }
730
+ return Math.max(0, Math.round(result));
731
+ }
732
+ function asFiniteNumber(value) {
733
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
734
+ }
735
+ function hasOverlap(start, end, occupied) {
736
+ for (let i = start; i <= end; i++) {
737
+ if (occupied.has(i)) {
738
+ return true;
739
+ }
740
+ }
741
+ return false;
742
+ }
743
+ function buildWidthesPrefixSums(values) {
744
+ const prefix = new Array(values.length + 1).fill(0);
745
+ for (let i = 0; i < values.length; i++) {
746
+ prefix[i + 1] = prefix[i] + values[i];
747
+ }
748
+ return prefix;
749
+ }
750
+ function sumByRange(prefix, start, end) {
751
+ return prefix[end + 1] - prefix[start];
752
+ }
753
+
754
+ /**
755
+ * Calculates the visual state of an overlay scrollbar. All arguments are raw DOM numbers.
756
+ * Returns a state describing the visibility, size, and position of the thumb.
757
+ */
758
+ function computeScrollbarState(scrollHeight = 0, clientHeight = 0, scrollTop = 0, minThumb = 24) {
759
+ const safeClient = toSafe(clientHeight);
760
+ const safeScrollH = toSafe(scrollHeight);
761
+ const safeTop = clamp(scrollTop, 0, Math.max(0, safeScrollH - safeClient));
762
+ if (safeClient <= 0 || !isFinite(safeClient)) {
763
+ return hiddenState();
764
+ }
765
+ if (safeScrollH <= safeClient + 1) {
766
+ return hiddenState(safeClient);
767
+ }
768
+ const track = safeClient;
769
+ const ratio = track / safeScrollH;
770
+ const thumb = Math.max(minThumb, Math.floor(track * ratio));
771
+ const maxScrollTop = Math.max(1, safeScrollH - track);
772
+ const maxThumbTop = Math.max(1, track - thumb);
773
+ const topRaw = Math.round((safeTop / maxScrollTop) * maxThumbTop);
774
+ const thumbTop = clamp(isFinite(topRaw) ? topRaw : 0, 0, maxThumbTop);
775
+ return {
776
+ visible: true,
777
+ thumbHeight: thumb,
778
+ thumbTop,
779
+ track,
780
+ maxThumbTop,
781
+ maxScrollTop,
782
+ };
783
+ }
784
+ /** Converts thumb position thumbTop (0..maxThumbTop) to scroll position scrollTop (0..maxScrollTop) */
785
+ function mapThumbTopToScrollTop(thumbTop, maxThumbTop, maxScrollTop) {
786
+ const mt = Math.max(1, toSafe(maxThumbTop));
787
+ const ms = Math.max(1, toSafe(maxScrollTop));
788
+ const tt = clamp(toSafe(thumbTop), 0, mt);
789
+ return (tt / mt) * ms;
790
+ }
791
+ /** Clamps the new thumb position within bounds 0..maxThumbTop */
792
+ function clampThumbTop(value, maxThumbTop) {
793
+ const mt = Math.max(1, toSafe(maxThumbTop));
794
+ return clamp(toSafe(value), 0, mt);
795
+ }
796
+ function hiddenState(track = 0) {
797
+ return {
798
+ visible: false,
799
+ thumbHeight: 0,
800
+ thumbTop: 0,
801
+ track,
802
+ maxThumbTop: 1,
803
+ maxScrollTop: 1,
804
+ };
805
+ }
806
+ function toSafe(n) {
807
+ return Number.isFinite(n) ? n : 0;
808
+ }
809
+ function clamp(v, min, max) {
810
+ if (v < min) {
811
+ return min;
812
+ }
813
+ if (v > max) {
814
+ return max;
815
+ }
816
+ return v;
817
+ }
818
+
819
+ /**
820
+ * Detects the primary scroll direction of an HTML element.
821
+ *
822
+ * Compares the current scroll position with the previous one to determine
823
+ * whether the user is scrolling horizontally, vertically, or not at all.
824
+ *
825
+ * Example:
826
+ * ```typescript
827
+ * const detector = new ScrollDirectionDetector(scrollableDiv);
828
+ *
829
+ * scrollableDiv.addEventListener('scroll', () => {
830
+ * const direction = detector.detect();
831
+ * console.log('Scroll direction:', direction); // 'horizontal' | 'vertical' | 'none'
832
+ * });
833
+ * ```
834
+ *
835
+ * The detector stores the previous scroll position internally and updates it
836
+ * on each `detect()` call to track movement deltas.
837
+ */
838
+ class ScrollDirectionDetector {
839
+ el;
840
+ /**
841
+ * Previously recorded vertical scroll position (scrollTop).
842
+ * @private
843
+ */
844
+ #prevTop = 0;
845
+ /**
846
+ * Previously recorded horizontal scroll position (scrollLeft).
847
+ * @private
848
+ */
849
+ #prevLeft = 0;
850
+ /**
851
+ * Creates a new scroll direction detector for the given HTML element.
852
+ *
853
+ * @param el - The HTML element whose scroll direction will be tracked.
854
+ * The element must be scrollable (have overflow content).
855
+ */
856
+ constructor(el) {
857
+ this.el = el;
858
+ this.#prevTop = el.scrollTop;
859
+ this.#prevLeft = el.scrollLeft;
860
+ }
861
+ /**
862
+ * Detects the primary scroll direction based on position changes since the last call.
863
+ *
864
+ * Compares the absolute deltas of horizontal and vertical scroll positions.
865
+ * The direction with the greater delta is considered the primary scroll direction.
866
+ *
867
+ * @returns The detected scroll direction:
868
+ * - `'horizontal'` if horizontal movement is greater
869
+ * - `'vertical'` if vertical movement is greater
870
+ * - `'none'` if no scroll movement occurred or deltas are equal
871
+ */
872
+ detect() {
873
+ const { scrollTop, scrollLeft } = this.el;
874
+ const deltaX = Math.abs(scrollLeft - this.#prevLeft);
875
+ const deltaY = Math.abs(scrollTop - this.#prevTop);
876
+ this.#prevTop = scrollTop;
877
+ this.#prevLeft = scrollLeft;
878
+ if (deltaX === 0 && deltaY === 0)
879
+ return 'none';
880
+ if (deltaX > deltaY)
881
+ return 'horizontal';
882
+ if (deltaY > deltaX)
883
+ return 'vertical';
884
+ return 'none';
885
+ }
886
+ }
887
+
888
+ /**
889
+ * Splits an array of grid columns into sticky left, sticky right, and all visible columns.
890
+ *
891
+ * This function filters columns by visibility, then divides them at the midpoint
892
+ * to identify which sticky columns should be pinned to the left versus right side
893
+ * of the data grid.
894
+ *
895
+ * @template Data - The data type extending `AnyDict` that the grid columns are based on.
896
+ * @param cols - Array of grid columns to be split.
897
+ * @returns An object containing:
898
+ * - `left`: Array of sticky columns from the first half of visible columns.
899
+ * - `right`: Array of sticky columns from the second half of visible columns.
900
+ * - `visible`: Array of all visible columns (filtered by `visible !== false`).
901
+ *
902
+ * @example
903
+ * ```typescript
904
+ * const columns: GridColumn<User>[] = [...];
905
+ * const { left, right, visible } = splitSticky(columns);
906
+ * ```
907
+ */
908
+ function splitSticky(cols) {
909
+ const visible = cols.filter((c) => c.visible !== false);
910
+ const left = visible.filter((col) => col.sticky === 'left' || col.sticky === true);
911
+ const right = visible.filter((col) => col.sticky === 'right');
912
+ return { left, right, visible };
913
+ }
914
+
915
+ /**
916
+ * View model for the data grid component.
917
+ *
918
+ * Manages grid state including column layout, sticky positioning, scrollbar calculations,
919
+ * and pinned rows. Automatically recomputes column widths based on container size and
920
+ * handles sticky column offsets for left and right pinned columns.
921
+ *
922
+ * @template Data - Type of data objects in the grid, must extend AnyDict
923
+ *
924
+ * @example
925
+ * ```typescript
926
+ * const gridVm = inject(DataGridVm<MyDataType>);
927
+ * gridVm.columns.set([{ key: 'name', title: 'Name' }]);
928
+ * gridVm.containerWidth.set(800);
929
+ * ```
930
+ */
931
+ class DataGridVm {
932
+ /**
933
+ * Reference to the scrollable container element.
934
+ *
935
+ * Used for scrollbar calculations and scroll position management.
936
+ */
937
+ scrollEl = signal(undefined, ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
938
+ /**
939
+ * Array of column configurations for the grid.
940
+ *
941
+ * Defines all columns including their keys, titles, sticky positioning, and widths.
942
+ * Value is reactive and triggers column layout recalculation when changed.
943
+ */
944
+ columns = signal([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
945
+ /**
946
+ * Array of pinned row configurations.
947
+ *
948
+ * Defines rows that remain fixed at the top or bottom of the grid during scrolling.
949
+ * Each row includes data, position ('top' or 'bottom'), and optional ordering.
950
+ */
951
+ pinnedRows = signal([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
952
+ headerGroups = signal([], ...(ngDevMode ? [{ debugName: "headerGroups" }] : []));
953
+ /**
954
+ * Current width of the grid container in pixels.
955
+ *
956
+ * Used for column width calculations and layout adjustments.
957
+ * Value is reactive and triggers column layout recalculation when changed.
958
+ */
959
+ containerWidth = signal(0, ...(ngDevMode ? [{ debugName: "containerWidth" }] : []));
960
+ /**
961
+ * Flag indicating whether the custom scrollbar should be visible.
962
+ *
963
+ * Automatically computed based on content height vs. container height.
964
+ */
965
+ scrollbarVisible = signal(false, ...(ngDevMode ? [{ debugName: "scrollbarVisible" }] : []));
966
+ /**
967
+ * Height of the scrollbar thumb in pixels.
968
+ *
969
+ * Proportional to the ratio of visible content to total content height.
970
+ */
971
+ thumbHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbHeightPx" }] : []));
972
+ /**
973
+ * Top position of the scrollbar thumb in pixels.
974
+ *
975
+ * Corresponds to the current scroll position within the scrollable area.
976
+ */
977
+ thumbTopPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbTopPx" }] : []));
978
+ /**
979
+ * Flag indicating whether the user is currently dragging the scrollbar thumb.
980
+ *
981
+ * Used to track active scroll drag interactions.
982
+ */
983
+ dragging = false;
984
+ /**
985
+ * Map of global cell renderer templates by type.
986
+ *
987
+ * Stores reusable template references for different cell renderer types
988
+ * that can be shared across multiple columns.
989
+ */
990
+ globalTypeCellTpls = new Map();
991
+ globalDataCellTpls = new Map();
992
+ globalRowCellTpls = new Map();
993
+ #byKey = signal({}, ...(ngDevMode ? [{ debugName: "#byKey" }] : []));
994
+ #defaultColWidth = 140;
995
+ #stickyLeftMap = new Map();
996
+ #stickyRightMap = new Map();
997
+ #stickySplit = computed(() => splitSticky(this.columns() ?? []), ...(ngDevMode ? [{ debugName: "#stickySplit" }] : []));
998
+ #layoutSignature = '';
999
+ #stickySignature = '';
1000
+ pinnedTop = signal([], ...(ngDevMode ? [{ debugName: "pinnedTop" }] : []));
1001
+ pinnedBottom = signal([], ...(ngDevMode ? [{ debugName: "pinnedBottom" }] : []));
1002
+ /**
1003
+ * Computed an array of non-sticky columns to display in the scrollable area.
1004
+ *
1005
+ * Automatically splits columns into left-sticky, visible, and right-sticky groups,
1006
+ * recomputes sticky offsets, and returns only the scrollable middle section.
1007
+ * Recalculates whenever columns or container width changes.
1008
+ */
1009
+ columnsToShow = computed(() => {
1010
+ this.containerWidth();
1011
+ return this.#stickySplit().visible;
1012
+ }, ...(ngDevMode ? [{ debugName: "columnsToShow" }] : []));
1013
+ contentWidth = computed(() => {
1014
+ const columns = this.columnsToShow();
1015
+ if (!columns.length) {
1016
+ return 0;
1017
+ }
1018
+ return columns.reduce((sum, col) => sum + this.widthByKey(col.key), 0);
1019
+ }, ...(ngDevMode ? [{ debugName: "contentWidth" }] : []));
1020
+ /**
1021
+ * Computed array of normalized header groups with calculated widths.
1022
+ *
1023
+ * Transforms raw header group configurations into normalized structures
1024
+ * that include computed column widths for layout rendering. Returns an empty
1025
+ * array if no headers or columns are configured. Recalculates whenever
1026
+ * header groups or visible columns change.
1027
+ *
1028
+ * @returns Array of normalized header configurations with width calculations
1029
+ */
1030
+ normalizedHeaderGroups = computed(() => {
1031
+ const headers = this.headerGroups();
1032
+ const columns = this.columnsToShow();
1033
+ if (!headers.length || !columns.length) {
1034
+ return [];
1035
+ }
1036
+ const normalizedColumns = columns.map((col) => ({
1037
+ ...col,
1038
+ width: this.widthByKey(col.key),
1039
+ }));
1040
+ return computeHeaderGroups(headers, normalizedColumns);
1041
+ }, ...(ngDevMode ? [{ debugName: "normalizedHeaderGroups" }] : []));
1042
+ constructor() {
1043
+ effect(() => {
1044
+ const rows = this.pinnedRows() ?? [];
1045
+ this.pinnedTop.set(rows.filter((r) => r.position === 'top').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)));
1046
+ this.pinnedBottom.set(rows.filter((r) => r.position === 'bottom').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)));
1047
+ });
1048
+ effect(() => {
1049
+ const cols = this.columns();
1050
+ const width = this.containerWidth();
1051
+ if (!cols.length || !width) {
1052
+ return;
1053
+ }
1054
+ const signature = this.layoutSignature(cols, width);
1055
+ if (signature === this.#layoutSignature) {
1056
+ return;
1057
+ }
1058
+ this.#layoutSignature = signature;
1059
+ const res = layoutColumns(cols, width, this.#defaultColWidth);
1060
+ this.#byKey.set(res.byKey);
1061
+ });
1062
+ effect(() => {
1063
+ this.#byKey();
1064
+ const { left, right } = this.#stickySplit();
1065
+ const signature = this.stickySignature(left, right);
1066
+ if (signature === this.#stickySignature) {
1067
+ return;
1068
+ }
1069
+ this.#stickySignature = signature;
1070
+ this.recomputeStickyOffsets(left, right);
1071
+ });
1072
+ }
1073
+ /**
1074
+ * Returns the computed width for a column by its key.
1075
+ *
1076
+ * If the column width has not been calculated, returns the default column width.
1077
+ *
1078
+ * @param key - The unique identifier for the column
1079
+ * @returns Width in pixels
1080
+ */
1081
+ widthByKey = (key) => this.#byKey()[key] ?? this.#defaultColWidth;
1082
+ /**
1083
+ * Checks if a column is pinned to the left side of the grid.
1084
+ *
1085
+ * @param key - The unique identifier for the column
1086
+ * @returns `true` if the column is sticky on the left, `false` otherwise
1087
+ */
1088
+ isStickyLeft = (key) => this.#stickyLeftMap.has(key);
1089
+ /**
1090
+ * Checks if a column is pinned to the right side of the grid.
1091
+ *
1092
+ * @param key - The unique identifier for the column
1093
+ * @returns `true` if the column is sticky on the right, `false` otherwise
1094
+ */
1095
+ isStickyRight = (key) => this.#stickyRightMap.has(key);
1096
+ /**
1097
+ * Returns the horizontal offset for a sticky column.
1098
+ *
1099
+ * Calculates the distance from the specified edge (left or right) where the column
1100
+ * should be positioned. Returns `null` if the column is not sticky in the given direction.
1101
+ *
1102
+ * @param key - The unique identifier for the column
1103
+ * @param dir - The direction to check ('left' or 'right')
1104
+ * @returns Offset in pixels, or `null` if not sticky in the specified direction
1105
+ */
1106
+ stickyOffset = (key, dir) => dir === 'left' && this.isStickyLeft(key)
1107
+ ? (this.#stickyLeftMap.get(key) ?? null)
1108
+ : dir === 'right' && this.isStickyRight(key)
1109
+ ? (this.#stickyRightMap.get(key) ?? null)
1110
+ : null;
1111
+ /**
1112
+ * Calculates and updates scrollbar state based on the current scroll position.
1113
+ *
1114
+ * Computes whether the scrollbar should be visible, and if so, determines
1115
+ * the thumb height and position based on scroll height, client height, and scroll position.
1116
+ * Updates the corresponding signal properties with the calculated values.
1117
+ */
1118
+ calcScrollbar() {
1119
+ const el = this.scrollEl()?.nativeElement;
1120
+ if (!el)
1121
+ return;
1122
+ const state = computeScrollbarState(el.scrollHeight, el.clientHeight, el.scrollTop);
1123
+ if (!state.visible) {
1124
+ this.scrollbarVisible.set(false);
1125
+ this.thumbHeightPx.set(0);
1126
+ this.thumbTopPx.set(0);
1127
+ return;
1128
+ }
1129
+ this.thumbHeightPx.set(state.thumbHeight);
1130
+ this.thumbTopPx.set(state.thumbTop);
1131
+ }
1132
+ recomputeStickyOffsets(leftCols, rightCols) {
1133
+ let acc = 0;
1134
+ this.#stickyLeftMap.clear();
1135
+ for (const col of leftCols) {
1136
+ this.#stickyLeftMap.set(col.key, acc);
1137
+ acc += this.widthByKey(col.key);
1138
+ }
1139
+ acc = 0;
1140
+ this.#stickyRightMap.clear();
1141
+ for (let i = rightCols.length - 1; i >= 0; i--) {
1142
+ const col = rightCols[i];
1143
+ this.#stickyRightMap.set(col.key, acc);
1144
+ acc += this.widthByKey(col.key);
1145
+ }
1146
+ }
1147
+ layoutSignature(cols, width) {
1148
+ const parts = [`w:${width}`];
1149
+ for (const col of cols) {
1150
+ const anyCol = col;
1151
+ const key = String(col.key);
1152
+ const widthVal = anyCol['width'] ?? '';
1153
+ const min = anyCol['minWidth'] ?? '';
1154
+ const max = anyCol['maxWidth'] ?? '';
1155
+ const flex = anyCol['flex'] ?? '';
1156
+ const visible = anyCol['visible'] ?? '';
1157
+ const sticky = anyCol['sticky'] ?? '';
1158
+ parts.push([key, widthVal, min, max, flex, visible, sticky].join('|'));
1159
+ }
1160
+ return parts.join(';');
1161
+ }
1162
+ stickySignature(leftCols, rightCols) {
1163
+ const left = leftCols.map((col) => `${col.key}:${this.widthByKey(col.key)}`).join(',');
1164
+ const right = rightCols.map((col) => `${col.key}:${this.widthByKey(col.key)}`).join(',');
1165
+ return `l:${left}|r:${right}`;
1166
+ }
1167
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1168
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm });
1169
+ }
1170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm, decorators: [{
1171
+ type: Injectable
1172
+ }], ctorParameters: () => [] });
1173
+
1174
+ // noinspection ES6PreferShortImport
1175
+ /**
1176
+ * Component for rendering individual data grid cells.
1177
+ *
1178
+ * Handles different cell rendering strategies based on column configuration:
1179
+ * - Custom templates via `renderTemplate`
1180
+ * - Global type-specific templates registered in DataGridVm
1181
+ * - Built-in formatters for dates and numbers
1182
+ * - Index display (1-based row numbering)
1183
+ * - Plain text for simple values
1184
+ *
1185
+ * The component automatically determines the appropriate rendering method
1186
+ * based on column properties and applies Angular pipes when needed.
1187
+ *
1188
+ * @template Data - Type of data objects in the grid row
1189
+ *
1190
+ * @example
1191
+ * ```html
1192
+ * <re-data-grid-cell
1193
+ * [index]="0"
1194
+ * [item]="rowData"
1195
+ * [column]="columnConfig"
1196
+ * />
1197
+ * ```
1198
+ */
1199
+ class DataGridCellComponent {
1200
+ /**
1201
+ * Zero-based index of the current row in the data grid.
1202
+ *
1203
+ * Used for rendering row numbers (displayed as 1-based in 'index' type columns)
1204
+ * and passed to custom templates as context.
1205
+ */
1206
+ index = input.required(...(ngDevMode ? [{ debugName: "index" }] : []));
1207
+ /**
1208
+ * Data object for the current row.
1209
+ *
1210
+ * Contains the complete row data that can be accessed by column value functions
1211
+ * or custom render templates. Type-safe, according to the Data generic parameter.
1212
+ */
1213
+ item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
1214
+ /**
1215
+ * Column configuration object.
1216
+ *
1217
+ * Defines how the cell should be rendered, including key mapping, type,
1218
+ * custom templates, or value transformation functions.
1219
+ */
1220
+ column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
1221
+ /**
1222
+ * Injected DataGridVm service instance.
1223
+ *
1224
+ * Provides access to global type-specific cell templates registered
1225
+ * at the grid level via the ` globalTypeCellTpls ` map.
1226
+ */
1227
+ vm = inject(DataGridVm);
1228
+ /**
1229
+ * Computed rendering strategy for the current cell.
1230
+ *
1231
+ * Determines which template block to use based on column configuration:
1232
+ * - `'tpl'` - Custom column template (`renderTemplate` property exists)
1233
+ * - `'globalTypeTpl'` - Global type template (registered in DataGridVm)
1234
+ * - `'date'`, `'number'`, `'index'` - Built-in formatters
1235
+ * - `'plain'` - Default text rendering
1236
+ *
1237
+ * The value is reactive and updates when the column configuration changes.
1238
+ */
1239
+ type = computed(() => {
1240
+ const col = this.column();
1241
+ if ('renderTemplate' in col) {
1242
+ return 'tpl';
1243
+ }
1244
+ if ('type' in col && this.vm.globalTypeCellTpls.has(col.type)) {
1245
+ return 'globalTypeTpl';
1246
+ }
1247
+ if (this.vm.globalDataCellTpls.has(col.key)) {
1248
+ return 'globalDataTpl';
1249
+ }
1250
+ if (this.vm.globalRowCellTpls.has(col.key)) {
1251
+ return 'globalRowTpl';
1252
+ }
1253
+ return 'type' in col ? col['type'] : 'plain';
1254
+ }, ...(ngDevMode ? [{ debugName: "type" }] : []));
1255
+ /**
1256
+ * Computed cell value extracted from row data.
1257
+ *
1258
+ * Returns the cell's display value by either:
1259
+ * - Calling the `value` function from column configuration (if defined)
1260
+ * - Directly accessing the row property using the column's `key`
1261
+ *
1262
+ * The value is reactive and updates when row data or column configuration changes.
1263
+ * Used as input for templates, pipes, and default text rendering.
1264
+ */
1265
+ value = computed(() => {
1266
+ const col = this.column();
1267
+ const row = this.item();
1268
+ const rawValue = 'value' in col ? col.value(row) : row[col.key];
1269
+ if ('value' in col || 'renderTemplate' in col) {
1270
+ return rawValue;
1271
+ }
1272
+ if (rawValue === null || rawValue === undefined) {
1273
+ return col.defaultValue ?? rawValue;
1274
+ }
1275
+ return rawValue;
1276
+ }, ...(ngDevMode ? [{ debugName: "value" }] : []));
1277
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1278
+ 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: `
1279
+ @let row = item();
1280
+ @let col = $any(column());
1281
+ @let val = value();
1282
+
1283
+ @switch (type()) {
1284
+ @case ('tpl') {
1285
+ <ng-container
1286
+ [ngTemplateOutlet]="col.renderTemplate"
1287
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1288
+ />
1289
+ }
1290
+ @case ('globalTypeTpl') {
1291
+ <ng-container
1292
+ [ngTemplateOutlet]="vm.globalTypeCellTpls.get(col.type)"
1293
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1294
+ />
1295
+ }
1296
+ @case ('globalDataTpl') {
1297
+ <ng-container
1298
+ [ngTemplateOutlet]="vm.globalDataCellTpls.get(col.key)"
1299
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1300
+ />
1301
+ }
1302
+ @case ('globalRowTpl') {
1303
+ <ng-container
1304
+ [ngTemplateOutlet]="vm.globalRowCellTpls.get(col.key)"
1305
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1306
+ />
1307
+ }
1308
+ @case ('date') {
1309
+ <span class="re-dg-cell-text">{{ val | date: col?.typeParams }}</span>
1310
+ }
1311
+ @case ('number') {
1312
+ <span class="re-dg-cell-text">{{ val | number: col?.typeParams }}</span>
1313
+ }
1314
+ @case ('index') {
1315
+ <span class="re-dg-cell-text">{{ index() + 1 }}</span>
1316
+ }
1317
+ @default {
1318
+ <span class="re-dg-cell-text">{{ val }}</span>
1319
+ }
1320
+ }
1321
+ `, isInline: true, styles: [":host{display:block;width:100%;min-width:0;text-align:inherit}.re-dg-cell-text{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;line-height:var(--re-data-grid-cell-line-height, 1.2);-webkit-box-orient:vertical;-webkit-line-clamp:var(--re-data-grid-cell-max-lines, 2)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: DecimalPipe, name: "number" }] });
1322
+ }
1323
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellComponent, decorators: [{
1324
+ type: Component,
1325
+ args: [{ selector: 're-data-grid-cell', template: `
1326
+ @let row = item();
1327
+ @let col = $any(column());
1328
+ @let val = value();
1329
+
1330
+ @switch (type()) {
1331
+ @case ('tpl') {
1332
+ <ng-container
1333
+ [ngTemplateOutlet]="col.renderTemplate"
1334
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1335
+ />
1336
+ }
1337
+ @case ('globalTypeTpl') {
1338
+ <ng-container
1339
+ [ngTemplateOutlet]="vm.globalTypeCellTpls.get(col.type)"
1340
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1341
+ />
1342
+ }
1343
+ @case ('globalDataTpl') {
1344
+ <ng-container
1345
+ [ngTemplateOutlet]="vm.globalDataCellTpls.get(col.key)"
1346
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1347
+ />
1348
+ }
1349
+ @case ('globalRowTpl') {
1350
+ <ng-container
1351
+ [ngTemplateOutlet]="vm.globalRowCellTpls.get(col.key)"
1352
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index: index() }"
1353
+ />
1354
+ }
1355
+ @case ('date') {
1356
+ <span class="re-dg-cell-text">{{ val | date: col?.typeParams }}</span>
1357
+ }
1358
+ @case ('number') {
1359
+ <span class="re-dg-cell-text">{{ val | number: col?.typeParams }}</span>
1360
+ }
1361
+ @case ('index') {
1362
+ <span class="re-dg-cell-text">{{ index() + 1 }}</span>
1363
+ }
1364
+ @default {
1365
+ <span class="re-dg-cell-text">{{ val }}</span>
1366
+ }
1367
+ }
1368
+ `, imports: [NgTemplateOutlet, DatePipe, DecimalPipe], styles: [":host{display:block;width:100%;min-width:0;text-align:inherit}.re-dg-cell-text{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;line-height:var(--re-data-grid-cell-line-height, 1.2);-webkit-box-orient:vertical;-webkit-line-clamp:var(--re-data-grid-cell-max-lines, 2)}\n"] }]
1369
+ }], 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 }] }] } });
1370
+
1371
+ // noinspection ES6PreferShortImport
1372
+ function createGridApiFeature(ctx) {
1373
+ const clearSelection = () => {
1374
+ const selectionFeature = ctx.getSelectionFeature();
1375
+ if (selectionFeature) {
1376
+ selectionFeature.clearSelection();
1377
+ return;
1378
+ }
1379
+ ctx.clearSelectedKeys();
1380
+ ctx.emitSelectChange([]);
1381
+ void ctx.loadSelectionFeature();
1382
+ };
1383
+ const selectAllLoaded = () => {
1384
+ const selectionFeature = ctx.getSelectionFeature();
1385
+ if (selectionFeature) {
1386
+ selectionFeature.selectAllLoaded();
1387
+ return;
1388
+ }
1389
+ if (ctx.getSelectionMode() !== 'multi') {
1390
+ return;
1391
+ }
1392
+ ctx.emitSelectChange(ctx.selectAll());
1393
+ void ctx.loadSelectionFeature();
1394
+ };
1395
+ return {
1396
+ clearSelection,
1397
+ selectAllLoaded,
1398
+ resetSort: () => ctx.resetSort(),
1399
+ setSort: (sort) => ctx.setSort(sort),
1400
+ setMultiSort: (sorts) => ctx.setMultiSort(sorts),
1401
+ };
1402
+ }
1403
+
1404
+ // noinspection ES6PreferShortImport
1405
+ function createGridExpanderFeature(ctx) {
1406
+ const isExpandable = (column) => {
1407
+ return ctx.getExpanderMap().has(column.key);
1408
+ };
1409
+ const onExpand = (column) => {
1410
+ const expanded = !ctx.getExpanderMap().get(column.key);
1411
+ ctx.updateExpanderMap((prev) => {
1412
+ const map = new Map(prev);
1413
+ map.set(column.key, expanded);
1414
+ return map;
1415
+ });
1416
+ const columns = ctx
1417
+ .getExtendedColumns()
1418
+ .map((col) => (col.expandBy === column.key ? { ...col, visible: expanded } : col));
1419
+ ctx.setVmColumns(columns);
1420
+ };
1421
+ const initExpander = () => {
1422
+ const map = new Map();
1423
+ const columns = ctx.runUntracked(() => ctx.getVmColumns().map((col) => {
1424
+ col.expandBy && map.set(col.expandBy, false);
1425
+ return { ...col, visible: col.expandBy ? false : col.visible };
1426
+ }));
1427
+ ctx.setVmColumns(columns);
1428
+ ctx.setExpanderMap(map);
1429
+ };
1430
+ return {
1431
+ isExpandable,
1432
+ onExpand,
1433
+ initExpander,
1434
+ };
1435
+ }
1436
+
1437
+ // noinspection ES6PreferShortImport
1438
+ function createGridHeaderGroupsFeature(ctx) {
1439
+ const sortOrderFor = (col) => {
1440
+ if (!col.sortKey) {
1441
+ return undefined;
1442
+ }
1443
+ if (ctx.getSortMode() === 'multi') {
1444
+ return ctx.getMultiSortMap().get(col.sortKey);
1445
+ }
1446
+ if (ctx.getSingleSortField() !== col.sortKey) {
1447
+ return undefined;
1448
+ }
1449
+ return ctx.getSingleSortOrder();
1450
+ };
1451
+ const ariaSort = (col) => {
1452
+ const order = sortOrderFor(col);
1453
+ if (!order) {
1454
+ return 'none';
1455
+ }
1456
+ return order === 'asc' ? 'ascending' : 'descending';
1457
+ };
1458
+ const syncHeaderGroups = () => {
1459
+ ctx.setVmHeaderGroups(ctx.getHeaderGroups());
1460
+ };
1461
+ const isActiveSort = (col) => !!sortOrderFor(col);
1462
+ return {
1463
+ ariaSort,
1464
+ isActiveSort,
1465
+ sortOrderFor,
1466
+ syncHeaderGroups,
1467
+ };
1468
+ }
1469
+
1470
+ function createGridHeaderMeasureFeature(ctx) {
1471
+ let headerMeasureRafId = null;
1472
+ const scheduleMeasure = () => {
1473
+ if (headerMeasureRafId !== null) {
1474
+ return;
1475
+ }
1476
+ headerMeasureRafId = ctx.requestAnimationFrame(() => {
1477
+ headerMeasureRafId = null;
1478
+ const el = ctx.getHeaderElement();
1479
+ if (!el) {
1480
+ return;
1481
+ }
1482
+ ctx.setHeaderHeight(el.offsetHeight);
1483
+ });
1484
+ };
1485
+ const clearMeasure = () => {
1486
+ if (headerMeasureRafId === null) {
1487
+ return;
1488
+ }
1489
+ ctx.cancelAnimationFrame(headerMeasureRafId);
1490
+ headerMeasureRafId = null;
1491
+ };
1492
+ return {
1493
+ scheduleMeasure,
1494
+ clearMeasure,
1495
+ };
1496
+ }
1497
+
1498
+ function createGridInfinityPageRequestFeature(ctx) {
1499
+ const PREFETCH_FACTOR = 1.25;
1500
+ let lastRequestedPage = null;
1501
+ let lastTotal = -1;
1502
+ const onDataTotalChanged = (total) => {
1503
+ if (total === lastTotal) {
1504
+ return;
1505
+ }
1506
+ lastTotal = total;
1507
+ lastRequestedPage = null;
1508
+ };
1509
+ const requestIfNeeded = (state) => {
1510
+ if (state.initial || state.mode !== 'infinity') {
1511
+ return false;
1512
+ }
1513
+ const threshold = Math.max(0, state.total - Math.max(1, Math.floor(state.visibleCount * PREFETCH_FACTOR)));
1514
+ const nearEnd = state.start + state.visibleCount >= threshold;
1515
+ if (!nearEnd || ctx.isLoading()) {
1516
+ return false;
1517
+ }
1518
+ const modifier = ctx.isPageStartFromZero() ? 0 : 1;
1519
+ const page = Math.floor(state.total / ctx.getPageSize()) + modifier;
1520
+ if (lastRequestedPage === page && lastTotal === state.total) {
1521
+ return true;
1522
+ }
1523
+ lastTotal = state.total;
1524
+ lastRequestedPage = page;
1525
+ ctx.emitPageChange({ page, rows: ctx.getPageSize() });
1526
+ return false;
1527
+ };
1528
+ const reset = () => {
1529
+ lastRequestedPage = null;
1530
+ lastTotal = -1;
1531
+ };
1532
+ return {
1533
+ onDataTotalChanged,
1534
+ requestIfNeeded,
1535
+ reset,
1536
+ };
1537
+ }
1538
+
1539
+ function createGridLifecycleInitFeature(ctx) {
1540
+ const init = (plan) => {
1541
+ plan.afterRender.forEach((fn) => ctx.registerAfterRenderEffect(fn));
1542
+ plan.effects.forEach((fn) => ctx.registerEffect(fn));
1543
+ ctx.registerOnDestroy(plan.onDestroy);
1544
+ };
1545
+ return { init };
1546
+ }
1547
+
1548
+ function createGridResizeObserverFeature(ctx) {
1549
+ let observer;
1550
+ let lastResizeWidth = -1;
1551
+ let lastResizeHeight = -1;
1552
+ const resizeSubject = new Subject();
1553
+ const initObserver = () => {
1554
+ const root = ctx.getRootElement();
1555
+ if (!root) {
1556
+ return;
1557
+ }
1558
+ ctx.addSubscription(resizeSubject.pipe(debounceTime(ctx.getResizeDebounceMs())).subscribe((entries) => {
1559
+ const rect = entries[0].contentRect;
1560
+ const width = rect.width;
1561
+ const height = rect.height;
1562
+ const widthChanged = width !== lastResizeWidth;
1563
+ const heightChanged = height !== lastResizeHeight;
1564
+ if (!widthChanged && !heightChanged) {
1565
+ return;
1566
+ }
1567
+ lastResizeWidth = width;
1568
+ lastResizeHeight = height;
1569
+ if (widthChanged) {
1570
+ ctx.onWidthChanged(width);
1571
+ }
1572
+ if (heightChanged) {
1573
+ ctx.onHeightChanged(height);
1574
+ }
1575
+ }));
1576
+ observer = new ResizeObserver((entries) => resizeSubject.next(entries));
1577
+ observer.observe(root);
1578
+ };
1579
+ const disconnect = () => {
1580
+ observer?.disconnect();
1581
+ };
1582
+ return {
1583
+ initObserver,
1584
+ disconnect,
1585
+ };
1586
+ }
1587
+
1588
+ // noinspection ES6PreferShortImport
1589
+ function createGridRowInteractionsFeature(ctx) {
1590
+ const onCellClick = (row, col, index, event) => {
1591
+ if (ctx.isRowDisabled(row, index)) {
1592
+ return;
1593
+ }
1594
+ ctx.emitCellClick({ row, col, index, event });
1595
+ if (ctx.getSelectionMode() !== 'none') {
1596
+ ctx.emitSelectChange(ctx.selectRow(row));
1597
+ }
1598
+ };
1599
+ const onCellContext = (row, col, index, event) => {
1600
+ if (ctx.isRowDisabled(row, index)) {
1601
+ return;
1602
+ }
1603
+ ctx.emitCellContext({ row, col, index, event });
1604
+ };
1605
+ const onCellDoubleClick = (row, col, index, event) => {
1606
+ if (ctx.isRowDisabled(row, index)) {
1607
+ return;
1608
+ }
1609
+ ctx.emitCellDoubleClick({ row, col, index, event });
1610
+ };
1611
+ const onRowClick = (row, index, event) => {
1612
+ if (ctx.isRowDisabled(row, index)) {
1613
+ return;
1614
+ }
1615
+ event.stopPropagation();
1616
+ ctx.emitRowClick({ row, index, event });
1617
+ };
1618
+ const onRowContext = (row, index, event) => {
1619
+ if (ctx.isRowDisabled(row, index)) {
1620
+ return;
1621
+ }
1622
+ event.stopPropagation();
1623
+ ctx.emitRowContext({ row, index, event });
1624
+ };
1625
+ const onRowDoubleClick = (row, index, event) => {
1626
+ if (ctx.isRowDisabled(row, index)) {
1627
+ return;
1628
+ }
1629
+ event.stopPropagation();
1630
+ ctx.emitRowDoubleClick({ row, index, event });
1631
+ };
1632
+ return {
1633
+ onCellClick,
1634
+ onCellContext,
1635
+ onCellDoubleClick,
1636
+ onRowClick,
1637
+ onRowContext,
1638
+ onRowDoubleClick,
1639
+ };
1640
+ }
1641
+
1642
+ function createGridScrollLoopFeature(ctx) {
1643
+ let scrollRafId = null;
1644
+ const scheduleScrollTick = (detector) => {
1645
+ if (scrollRafId !== null) {
1646
+ return;
1647
+ }
1648
+ scrollRafId = requestAnimationFrame(() => {
1649
+ scrollRafId = null;
1650
+ const direction = detector.detect();
1651
+ ctx.runInAngular(() => {
1652
+ direction === 'vertical' ? ctx.onVerticalScroll() : ctx.onHorizontalScroll();
1653
+ ctx.hideTooltip();
1654
+ });
1655
+ });
1656
+ };
1657
+ const initScroll = () => {
1658
+ const scrollEl = ctx.getScrollElement();
1659
+ if (scrollEl) {
1660
+ const scrollDetector = new ScrollDirectionDetector(scrollEl);
1661
+ ctx.runOutsideAngular(() => {
1662
+ ctx.addSubscription(fromEvent(scrollEl, 'scroll').subscribe(() => scheduleScrollTick(scrollDetector)));
1663
+ ctx.addSubscription(fromEvent(scrollEl, 'scroll').subscribe(() => ctx.onStickySchedule()));
1664
+ });
1665
+ }
1666
+ queueMicrotask(() => ctx.onInitialVerticalScroll());
1667
+ };
1668
+ const clearScrollRaf = () => {
1669
+ if (scrollRafId === null) {
1670
+ return;
1671
+ }
1672
+ cancelAnimationFrame(scrollRafId);
1673
+ scrollRafId = null;
1674
+ };
1675
+ return {
1676
+ initScroll,
1677
+ clearScrollRaf,
1678
+ };
1679
+ }
1680
+
1681
+ // noinspection ES6PreferShortImport
1682
+ function createGridSelectionReconcileFeature(ctx) {
1683
+ let lastSelectionKeyField = '';
1684
+ let lastValidSelectionKeys = new Set();
1685
+ const reconcile = () => {
1686
+ const selection = ctx.getSelection();
1687
+ if (selection.mode === 'none' || !('key' in selection)) {
1688
+ lastSelectionKeyField = '';
1689
+ lastValidSelectionKeys.clear();
1690
+ return;
1691
+ }
1692
+ const data = ctx.getData() ?? [];
1693
+ const key = selection.key;
1694
+ const validKeys = data.map((row) => row[key]).filter((rowKey) => rowKey !== null && rowKey !== undefined);
1695
+ const keySet = new Set(validKeys);
1696
+ const keyField = String(key);
1697
+ const sameSetAsPrevious = lastSelectionKeyField === keyField &&
1698
+ keySet.size === lastValidSelectionKeys.size &&
1699
+ Array.from(keySet).every((rowKey) => lastValidSelectionKeys.has(rowKey));
1700
+ if (sameSetAsPrevious) {
1701
+ return;
1702
+ }
1703
+ lastSelectionKeyField = keyField;
1704
+ lastValidSelectionKeys = new Set(keySet);
1705
+ const nextSelected = ctx
1706
+ .getSelectedKeys()
1707
+ .filter((selectedKey) => selectedKey !== null && selectedKey !== undefined && keySet.has(selectedKey));
1708
+ ctx.setSelectedKeys(nextSelected);
1709
+ };
1710
+ return { reconcile };
1711
+ }
1712
+
1713
+ // noinspection ES6PreferShortImport
1714
+ function createGridSlotsFeature(ctx) {
1715
+ const initRefs = () => {
1716
+ ctx.clearTypeTemplates();
1717
+ ctx.clearDataTemplates();
1718
+ ctx.clearRowTemplates();
1719
+ ctx.getTypeTemplateRefs()?.forEach((dir) => ctx.setTypeTemplate(dir.type(), dir.tpl));
1720
+ ctx.getDataTemplateRefs()?.forEach((dir) => ctx.setDataTemplate(dir.key(), dir.tpl));
1721
+ for (const [key, tpl] of ctx.getRowTemplateEntries()) {
1722
+ ctx.setRowTemplate(key, tpl);
1723
+ }
1724
+ const headerMap = new Map();
1725
+ ctx.getHeaderTemplateRefs()?.forEach((headerRef) => headerMap.set(headerRef.key(), headerRef.tpl));
1726
+ ctx.getExtendedColumns().forEach((column) => {
1727
+ if (!column.headerTemplate && headerMap.has(column.key)) {
1728
+ column.headerTemplate = headerMap.get(column.key);
1729
+ }
1730
+ });
1731
+ };
1732
+ return { initRefs };
1733
+ }
1734
+
1735
+ // noinspection ES6PreferShortImport
1736
+ function createGridSortFeature(ctx) {
1737
+ const resetSort = () => {
1738
+ const prevKey = (ctx.getSortField() ?? '');
1739
+ ctx.setSortField(undefined);
1740
+ ctx.setSorts([]);
1741
+ ctx.emitSortChange({ key: prevKey, order: undefined });
1742
+ ctx.emitMultiSortChange([]);
1743
+ };
1744
+ const setSort = (sort) => {
1745
+ if (!sort.key || !sort.order) {
1746
+ resetSort();
1747
+ return;
1748
+ }
1749
+ ctx.setSortField(String(sort.key));
1750
+ ctx.setSortOrder(sort.order);
1751
+ ctx.setSorts([{ key: sort.key, order: sort.order }]);
1752
+ ctx.emitSortChange({ key: sort.key, order: sort.order });
1753
+ ctx.getSortMode() === 'multi' && ctx.emitMultiSortChange(ctx.getSorts());
1754
+ };
1755
+ const setMultiSort = (sorts) => {
1756
+ const normalizedSorts = (sorts ?? []).filter((sort) => !!sort?.key && !!sort?.order);
1757
+ if (!normalizedSorts.length) {
1758
+ resetSort();
1759
+ return;
1760
+ }
1761
+ const active = normalizedSorts[normalizedSorts.length - 1];
1762
+ ctx.setSortField(String(active.key));
1763
+ ctx.setSortOrder(active.order);
1764
+ ctx.setSorts([...normalizedSorts]);
1765
+ ctx.emitSortChange({ key: active.key, order: active.order });
1766
+ ctx.emitMultiSortChange(ctx.getSorts());
1767
+ };
1768
+ const onSort = (sortKey) => {
1769
+ if (!sortKey) {
1770
+ return;
1771
+ }
1772
+ if (ctx.getSortMode() === 'multi') {
1773
+ const currentSorts = ctx.getSorts();
1774
+ const existingIndex = currentSorts.findIndex((item) => item.key === sortKey);
1775
+ if (existingIndex >= 0) {
1776
+ const current = currentSorts[existingIndex];
1777
+ if (current.order === 'asc') {
1778
+ ctx.setSorts(currentSorts.map((item, index) => (index === existingIndex ? { ...item, order: 'desc' } : item)));
1779
+ }
1780
+ else {
1781
+ ctx.setSorts(currentSorts.filter((item) => item.key !== sortKey));
1782
+ }
1783
+ }
1784
+ else {
1785
+ ctx.setSorts([...currentSorts, { key: sortKey, order: 'asc' }]);
1786
+ }
1787
+ const activeOrder = ctx.getSortOrderByKey(sortKey);
1788
+ ctx.setSortField(sortKey);
1789
+ activeOrder && ctx.setSortOrder(activeOrder);
1790
+ ctx.emitSortChange({ key: sortKey, order: activeOrder });
1791
+ ctx.emitMultiSortChange(ctx.getSorts());
1792
+ return;
1793
+ }
1794
+ if (ctx.getSortField() === sortKey) {
1795
+ if (ctx.getSortOrder() === 'asc') {
1796
+ ctx.setSortOrder('desc');
1797
+ ctx.setSorts([{ key: sortKey, order: 'desc' }]);
1798
+ }
1799
+ else {
1800
+ ctx.setSortField(undefined);
1801
+ ctx.setSorts([]);
1802
+ }
1803
+ }
1804
+ else {
1805
+ ctx.setSortField(sortKey);
1806
+ ctx.setSortOrder('asc');
1807
+ ctx.setSorts([{ key: sortKey, order: 'asc' }]);
1808
+ }
1809
+ ctx.emitSortChange({
1810
+ key: sortKey,
1811
+ order: ctx.getSortField() ? ctx.getSortOrder() : undefined,
1812
+ });
1813
+ };
1814
+ return { resetSort, setSort, setMultiSort, onSort };
1815
+ }
1816
+
1817
+ function createGridStickyOrchestrationFeature(ctx) {
1818
+ const reconcile = () => {
1819
+ const data = ctx.getData();
1820
+ const predicate = ctx.getStickyPredicate();
1821
+ if (!predicate || !data.length) {
1822
+ ctx.setStickyIndexes([]);
1823
+ ctx.updateStickyFromScroll();
1824
+ return;
1825
+ }
1826
+ ctx.ensureStickyFeatureLoaded();
1827
+ const indexes = [];
1828
+ for (let i = 0; i < data.length; i++) {
1829
+ if (predicate(data[i], i)) {
1830
+ indexes.push(i);
1831
+ }
1832
+ }
1833
+ ctx.setStickyIndexes(indexes);
1834
+ ctx.updateStickyFromScroll();
1835
+ };
1836
+ return { reconcile };
1837
+ }
1838
+
1839
+ // noinspection ES6PreferShortImport
1840
+ function createGridTooltipAdapterFeature(ctx) {
1841
+ const preloadForColumns = (columns) => {
1842
+ if (!columns.some((col) => !!col.tooltip)) {
1843
+ return;
1844
+ }
1845
+ void ctx.loadTooltipFeature();
1846
+ };
1847
+ const showTooltip = (event, row, col, index) => {
1848
+ if (!col.tooltip) {
1849
+ return;
1850
+ }
1851
+ const feature = ctx.getTooltipFeature();
1852
+ if (feature) {
1853
+ feature.showTooltip(event, row, col, index);
1854
+ return;
1855
+ }
1856
+ void ctx.loadTooltipFeature();
1857
+ };
1858
+ const hideTooltip = () => {
1859
+ ctx.getTooltipFeature()?.hideTooltip();
1860
+ };
1861
+ const positionTooltip = () => {
1862
+ const feature = ctx.getTooltipFeature();
1863
+ if (!feature) {
1864
+ return;
1865
+ }
1866
+ feature.positionTooltip(ctx.getTooltipElement());
1867
+ };
1868
+ return {
1869
+ preloadForColumns,
1870
+ showTooltip,
1871
+ hideTooltip,
1872
+ positionTooltip,
1873
+ };
1874
+ }
1875
+
1876
+ // noinspection ES6PreferShortImport
1877
+ function createGridVirtualScrollFeature(ctx) {
1878
+ const ensureRenderSlots = (count) => {
1879
+ const current = ctx.getRenderSlots();
1880
+ if (current.length === count) {
1881
+ return;
1882
+ }
1883
+ const next = new Array(count);
1884
+ for (let i = 0; i < count; i++) {
1885
+ next[i] = i;
1886
+ }
1887
+ ctx.setRenderSlots(next);
1888
+ };
1889
+ const onVerticalScroll = (initial = false) => {
1890
+ const el = ctx.getScrollElement();
1891
+ if (!el) {
1892
+ return;
1893
+ }
1894
+ const scrollTop = el.scrollTop ?? 0;
1895
+ const viewportHeight = el.clientHeight ?? 0;
1896
+ const data = ctx.getData() ?? [];
1897
+ const total = data.length ?? 0;
1898
+ const rowHeight = Math.max(1, ctx.getRowHeight());
1899
+ const virtualBuffer = Math.max(0, ctx.getVirtualBuffer());
1900
+ const pinnedTopH = ctx.getPinnedTopCount() * rowHeight;
1901
+ const limit = ctx.getMode() === 'pagination';
1902
+ const cap = limit ? Math.max(1, ctx.getPageSize()) : Number.POSITIVE_INFINITY;
1903
+ const viewportRows = Math.ceil(viewportHeight / rowHeight);
1904
+ const visibleCount = Math.min(viewportRows + virtualBuffer, cap);
1905
+ const start = Math.max(0, Math.floor(scrollTop / rowHeight) - Math.floor(virtualBuffer / 2));
1906
+ const end = Math.min(total, start + visibleCount);
1907
+ if (viewportHeight <= 0 || !isFinite(viewportHeight) || !isFinite(rowHeight)) {
1908
+ const fallbackCount = Math.min(total, Math.max(1, ctx.getPageSize()));
1909
+ ctx.setRenderCount(fallbackCount);
1910
+ ensureRenderSlots(fallbackCount);
1911
+ ctx.updateStickyRow(scrollTop, rowHeight, pinnedTopH);
1912
+ ctx.finalizeScroll();
1913
+ return;
1914
+ }
1915
+ const { start: lastStart, end: lastEnd } = ctx.getLastRange();
1916
+ if (start === lastStart && end === lastEnd) {
1917
+ ctx.finalizeScroll();
1918
+ return;
1919
+ }
1920
+ ctx.setLastRange({ start, end });
1921
+ ctx.setStartIndex(start);
1922
+ ctx.setRenderCount(Math.max(0, end - start));
1923
+ ensureRenderSlots(Math.max(0, end - start));
1924
+ ctx.updateStickyRow(scrollTop, rowHeight, pinnedTopH);
1925
+ const shouldSkipFinalize = ctx.requestInfinityIfNeeded({
1926
+ initial,
1927
+ mode: ctx.getMode(),
1928
+ total,
1929
+ start,
1930
+ visibleCount,
1931
+ });
1932
+ if (shouldSkipFinalize) {
1933
+ return;
1934
+ }
1935
+ ctx.finalizeScroll();
1936
+ };
1937
+ return { onVerticalScroll };
1938
+ }
1939
+
1940
+ /**
1941
+ * Merges declarative columns with programmatic columns.
1942
+ *
1943
+ * Declarative columns are treated as a base when present.
1944
+ * For matching keys we keep declarative values and fill only missing fields
1945
+ * from programmatic columns.
1946
+ */
1947
+ function mergeDeclarativeColumns(declarativeColumns = [], programmaticColumns = []) {
1948
+ if (!declarativeColumns.length) {
1949
+ return [...programmaticColumns];
1950
+ }
1951
+ if (!programmaticColumns.length) {
1952
+ return [...declarativeColumns];
1953
+ }
1954
+ const programmaticByKey = new Map(programmaticColumns.map((column) => [String(column.key), column]));
1955
+ const usedProgrammaticKeys = new Set();
1956
+ const merged = declarativeColumns.map((declarativeColumn) => {
1957
+ const key = String(declarativeColumn.key);
1958
+ const programmaticColumn = programmaticByKey.get(key);
1959
+ if (!programmaticColumn) {
1960
+ return declarativeColumn;
1961
+ }
1962
+ usedProgrammaticKeys.add(key);
1963
+ return mergeDefined(programmaticColumn, declarativeColumn);
1964
+ });
1965
+ const restProgrammatic = programmaticColumns.filter((column) => !usedProgrammaticKeys.has(String(column.key)));
1966
+ return [...merged, ...restProgrammatic];
1967
+ }
1968
+ function mergeDefined(source, overrides) {
1969
+ const result = { ...source };
1970
+ const overrideEntries = Object.entries(overrides);
1971
+ for (const [key, value] of overrideEntries) {
1972
+ if (value !== undefined) {
1973
+ result[key] = value;
1974
+ }
1975
+ }
1976
+ return result;
1977
+ }
1978
+
1979
+ // noinspection ES6PreferShortImport
1980
+ function normalizeDeclarativeColumns(defs = [], rowKey) {
1981
+ const columns = [];
1982
+ const rowCellTemplatesByKey = new Map();
1983
+ for (const def of defs) {
1984
+ const key = def.key;
1985
+ const base = {
1986
+ key,
1987
+ header: def.header ?? String(key),
1988
+ headerTemplate: def.headerTemplate,
1989
+ align: def.align,
1990
+ sortKey: def.sortKey,
1991
+ width: def.width,
1992
+ minWidth: def.minWidth,
1993
+ maxWidth: def.maxWidth,
1994
+ flex: def.flex,
1995
+ disabled: def.disabled,
1996
+ visible: def.visible,
1997
+ sticky: def.sticky,
1998
+ tooltip: def.tooltip,
1999
+ expandBy: def.expandBy,
2000
+ };
2001
+ if (def.cellTemplate) {
2002
+ rowCellTemplatesByKey.set(String(key), def.cellTemplate);
2003
+ }
2004
+ if (def.value) {
2005
+ columns.push({
2006
+ ...base,
2007
+ value: def.value,
2008
+ track: def.track ?? createDefaultTrack(key, rowKey),
2009
+ });
2010
+ continue;
2011
+ }
2012
+ columns.push({
2013
+ ...base,
2014
+ type: def.type ?? 'plain',
2015
+ typeParams: def.typeParams,
2016
+ defaultValue: def.defaultValue,
2017
+ });
2018
+ }
2019
+ return { columns, rowCellTemplatesByKey };
2020
+ }
2021
+ function createDefaultTrack(key, rowKey) {
2022
+ return (row) => {
2023
+ if (!rowKey) {
2024
+ return String(row[key]);
2025
+ }
2026
+ if (typeof rowKey === 'function') {
2027
+ return String(rowKey(row));
2028
+ }
2029
+ return String(row[rowKey]);
2030
+ };
2031
+ }
2032
+
2033
+ /**
2034
+ * Service class for managing row selection in a data grid.
2035
+ *
2036
+ * Handles selection state and operations for grid rows, supporting multiple selection modes
2037
+ * (none, single, multi). Provides reactive signals for tracking selected items and
2038
+ * computed values for selection state.
2039
+ *
2040
+ * @template Data - The type of data objects in the grid, must extend `AnyDict`.
2041
+ *
2042
+ * @example
2043
+ * ```typescript
2044
+ * const selector = new Selector<User>();
2045
+ * selector.data.set(users);
2046
+ * selector.selection.set({ mode: 'multi', key: 'id' });
2047
+ * selector.select(users[0]);
2048
+ * console.log(selector.selectedKeys()); // ['user-id']
2049
+ * ```
2050
+ */
2051
+ class Selector {
2052
+ /**
2053
+ * Signal containing the full dataset of grid rows.
2054
+ *
2055
+ * This signal holds all data items that can be selected.
2056
+ * Defaults to an empty array.
2057
+ */
2058
+ data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
2059
+ /**
2060
+ * Signal containing the current selection configuration.
2061
+ *
2062
+ * Defines the selection mode and the key property used for identifying rows.
2063
+ * Defaults to `{ mode: 'none' }` which disables selection.
2064
+ */
2065
+ selection = signal({ mode: 'none' }, ...(ngDevMode ? [{ debugName: "selection" }] : []));
2066
+ /**
2067
+ * Signal containing the array of currently selected row keys.
2068
+ *
2069
+ * Stores the keys of all selected rows based on the key property
2070
+ * defined in the selection configuration.
2071
+ * Defaults to an empty array.
2072
+ */
2073
+ selectedKeys = signal([], ...(ngDevMode ? [{ debugName: "selectedKeys" }] : []));
2074
+ selectedKeySet = computed(() => new Set(this.selectedKeys()), ...(ngDevMode ? [{ debugName: "selectedKeySet" }] : []));
2075
+ /**
2076
+ * Computed signal indicating the overall selection state of all rows.
2077
+ *
2078
+ * Returns:
2079
+ * - `true` if all rows are selected
2080
+ * - `false` if no rows are selected
2081
+ * - `'mixed'` if some but not all rows are selected
2082
+ *
2083
+ * Useful for implementing the "select all" checkbox with an indeterminate state.
2084
+ */
2085
+ isAllSelected = computed(() => {
2086
+ const selection = this.selection();
2087
+ if (!('key' in selection)) {
2088
+ return false;
2089
+ }
2090
+ const rows = this.data();
2091
+ if (!rows.length) {
2092
+ return false;
2093
+ }
2094
+ const selected = this.selectedKeySet();
2095
+ const loadedKeys = rows.map((row) => row[selection.key]).filter((key) => key !== null && key !== undefined);
2096
+ if (!loadedKeys.length) {
2097
+ return false;
2098
+ }
2099
+ let matched = 0;
2100
+ for (const key of loadedKeys) {
2101
+ selected.has(key) && matched++;
2102
+ }
2103
+ return matched === loadedKeys.length ? true : matched === 0 ? false : 'mixed';
2104
+ }, ...(ngDevMode ? [{ debugName: "isAllSelected" }] : []));
2105
+ /**
2106
+ * Checks whether a specific row is currently selected.
2107
+ *
2108
+ * Compares the row's key value against the list of selected keys.
2109
+ * Returns `false` if the selection mode is 'none' or the key is not configured.
2110
+ *
2111
+ * @param row - The data row to check selection status for.
2112
+ * @returns `true` if the row is selected, `false` otherwise.
2113
+ */
2114
+ isSelected(row) {
2115
+ const selection = this.selection();
2116
+ if (!('key' in selection)) {
2117
+ return false;
2118
+ }
2119
+ const rowKey = row[selection.key];
2120
+ if (rowKey === null || rowKey === undefined) {
2121
+ return false;
2122
+ }
2123
+ return this.selectedKeySet().has(rowKey);
2124
+ }
2125
+ /**
2126
+ * Toggles selection of all rows.
2127
+ *
2128
+ * If all rows are selected, deselects all.
2129
+ * If no rows or some rows are selected, selects all.
2130
+ *
2131
+ * This method only works in `'multi'` selection mode and throws an error
2132
+ * if called in any other mode.
2133
+ *
2134
+ * @returns The updated array of selected keys.
2135
+ * @throws {Error} If selection mode is not `'multi'`.
2136
+ */
2137
+ selectAll() {
2138
+ if (this.selection().mode !== 'multi') {
2139
+ throw new Error('Cannot select all in not "multi" mode');
2140
+ }
2141
+ const selection = this.selection();
2142
+ const loadedKeys = this.data()
2143
+ .map((row) => row[selection.key])
2144
+ .filter((key) => key !== null && key !== undefined);
2145
+ const loadedKeySet = new Set(loadedKeys);
2146
+ const selectedKeys = this.selectedKeys();
2147
+ const selectedSet = new Set(selectedKeys);
2148
+ const allLoadedSelected = loadedKeys.length > 0 && loadedKeys.every((key) => selectedSet.has(key));
2149
+ if (allLoadedSelected) {
2150
+ this.selectedKeys.set(selectedKeys.filter((key) => !loadedKeySet.has(key)));
2151
+ }
2152
+ else {
2153
+ const nextSelected = [...selectedKeys];
2154
+ for (const key of loadedKeys) {
2155
+ if (!selectedSet.has(key)) {
2156
+ nextSelected.push(key);
2157
+ selectedSet.add(key);
2158
+ }
2159
+ }
2160
+ this.selectedKeys.set(nextSelected);
2161
+ }
2162
+ return this.selectedKeys();
2163
+ }
2164
+ /**
2165
+ * Selects or deselects a specific row.
2166
+ *
2167
+ * Behavior depends on the selection mode:
2168
+ * - In `'single'` mode: replaces current selection with the specified row.
2169
+ * - In `'multi'` mode: toggles the row's selection state (adds if not selected, removes if selected).
2170
+ * - In `'none'` mode: throws an error.
2171
+ *
2172
+ * @param row - The data row to select or deselect.
2173
+ * @returns The updated array of selected keys after the operation.
2174
+ * @throws {Error} If selection mode is `'none'`.
2175
+ */
2176
+ select(row) {
2177
+ if (this.selection().mode === 'none') {
2178
+ throw new Error('Cannot select row in "none" mode');
2179
+ }
2180
+ const selection = this.selection();
2181
+ if (this.selection().mode === 'single') {
2182
+ const rowKey = row[selection.key];
2183
+ if (rowKey === null || rowKey === undefined) {
2184
+ return this.selectedKeys();
2185
+ }
2186
+ const selected = [rowKey];
2187
+ this.selectedKeys.set(selected);
2188
+ return selected;
2189
+ }
2190
+ else {
2191
+ const selectedKeys = this.selectedKeys();
2192
+ const selectedSet = this.selectedKeySet();
2193
+ const rowKey = row[selection.key];
2194
+ if (rowKey === null || rowKey === undefined) {
2195
+ return selectedKeys;
2196
+ }
2197
+ const has = selectedSet.has(rowKey);
2198
+ const selected = has ? selectedKeys.filter((it) => it !== rowKey) : [...selectedKeys, rowKey];
2199
+ this.selectedKeys.set(selected);
2200
+ return selected;
2201
+ }
2202
+ }
2203
+ }
2204
+
2205
+ // noinspection CssUnresolvedCustomProperty
2206
+ class CheckboxIcon {
2207
+ state = input(false, ...(ngDevMode ? [{ debugName: "state" }] : []));
2208
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
2209
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CheckboxIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
2210
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.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 } }, ngImport: i0, template: `
2211
+ <span
2212
+ class="cb"
2213
+ [class.cb--disabled]="disabled()"
2214
+ [class.cb--checked]="state() === true"
2215
+ [class.cb--mixed]="state() === 'mixed'"
2216
+ [attr.aria-checked]="state() === 'mixed' ? 'mixed' : state() ? 'true' : 'false'"
2217
+ [attr.aria-disabled]="disabled()"
2218
+ role="checkbox"
2219
+ aria-hidden="false"
2220
+ >
2221
+ <span class="cb__box" aria-hidden="true"></span>
2222
+ </span>
2223
+ `, 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__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--checked .cb__box{border-color:var(--re-data-grid-checkbox-active-color);background:var(--re-data-grid-checkbox-active-color)}.cb--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--mixed .cb__box{background:var(--re-data-grid-checkbox-active-color);border-color:var(--re-data-grid-checkbox-active-color)}.cb--mixed .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 });
2224
+ }
2225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CheckboxIcon, decorators: [{
2226
+ type: Component,
2227
+ args: [{ selector: 're-checkbox-ic', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
2228
+ <span
2229
+ class="cb"
2230
+ [class.cb--disabled]="disabled()"
2231
+ [class.cb--checked]="state() === true"
2232
+ [class.cb--mixed]="state() === 'mixed'"
2233
+ [attr.aria-checked]="state() === 'mixed' ? 'mixed' : state() ? 'true' : 'false'"
2234
+ [attr.aria-disabled]="disabled()"
2235
+ role="checkbox"
2236
+ aria-hidden="false"
2237
+ >
2238
+ <span class="cb__box" aria-hidden="true"></span>
2239
+ </span>
2240
+ `, 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__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--checked .cb__box{border-color:var(--re-data-grid-checkbox-active-color);background:var(--re-data-grid-checkbox-active-color)}.cb--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--mixed .cb__box{background:var(--re-data-grid-checkbox-active-color);border-color:var(--re-data-grid-checkbox-active-color)}.cb--mixed .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"] }]
2241
+ }], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
2242
+
2243
+ /* eslint-disable max-len */
2244
+ class ExpandIcon {
2245
+ expanded = input(false, { ...(ngDevMode ? { debugName: "expanded" } : {}), transform: booleanAttribute });
2246
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ExpandIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
2247
+ 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: `
2248
+ @if (expanded()) {
2249
+ <svg width="16" height="16" viewBox="0 0 16 16">
2250
+ <path
2251
+ 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"
2252
+ fill="var(--re-data-grid-expander-color)"
2253
+ />
2254
+ </svg>
2255
+ } @else {
2256
+ <svg width="16" height="16" viewBox="0 0 16 16">
2257
+ <path
2258
+ 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"
2259
+ fill="var(--re-data-grid-expander-color)"
2260
+ />
2261
+ </svg>
2262
+ }
2263
+ `, isInline: true, styles: [""] });
2264
+ }
2265
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ExpandIcon, decorators: [{
2266
+ type: Component,
2267
+ args: [{ selector: 're-expand-ic', template: `
2268
+ @if (expanded()) {
2269
+ <svg width="16" height="16" viewBox="0 0 16 16">
2270
+ <path
2271
+ 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"
2272
+ fill="var(--re-data-grid-expander-color)"
2273
+ />
2274
+ </svg>
2275
+ } @else {
2276
+ <svg width="16" height="16" viewBox="0 0 16 16">
2277
+ <path
2278
+ 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"
2279
+ fill="var(--re-data-grid-expander-color)"
2280
+ />
2281
+ </svg>
2282
+ }
2283
+ ` }]
2284
+ }], propDecorators: { expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }] } });
2285
+
2286
+ /* eslint-disable max-len */
2287
+ class SortIcon {
2288
+ direction = input('asc', ...(ngDevMode ? [{ debugName: "direction" }] : []));
2289
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SortIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
2290
+ 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: `
2291
+ <svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
2292
+ <path
2293
+ 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"
2294
+ fill="currentColor"
2295
+ />
2296
+ </svg>
2297
+ `, 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"] });
2298
+ }
2299
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SortIcon, decorators: [{
2300
+ type: Component,
2301
+ args: [{ selector: 're-sort-ic', template: `
2302
+ <svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
2303
+ <path
2304
+ 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"
2305
+ fill="currentColor"
2306
+ />
2307
+ </svg>
2308
+ `, styles: ["svg{transition:transform .3s ease-in-out}svg:not(.asc):not(.desc){display:none}.asc{transform:rotate(-180deg)}.desc{transform:rotate(0)}\n"] }]
2309
+ }], propDecorators: { direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }] } });
2310
+
2311
+ /**
2312
+ * Data grid component with virtual scrolling, sorting, selection, and pagination support.
2313
+ *
2314
+ * Provides high-performance rendering of large datasets with features like:
2315
+ * - Virtual scrolling for efficient DOM management
2316
+ * - Column sorting and expandable columns
2317
+ * - Row selection (single/multiple)
2318
+ * - Pagination modes: none, pagination, or infinite scroll
2319
+ * - Pinned rows
2320
+ * - Custom cell and header templates
2321
+ *
2322
+ * @example
2323
+ * ```html
2324
+ * <re-data-grid
2325
+ * [data]="users"
2326
+ * [columns]="columns"
2327
+ * [selection]="{ mode: 'multiple' }"
2328
+ * (sortChange)="onSort($event)"
2329
+ * />
2330
+ * ```
2331
+ */
2332
+ class DataGrid {
2333
+ defaults = inject(DATA_GRID_CONFIG) || DEFAULT_DATA_GRID_DEFAULTS;
2334
+ /**
2335
+ * Array of data to display in the table.
2336
+ *
2337
+ * Each item represents a single row. The component will efficiently render
2338
+ * only visible rows using virtual scrolling.
2339
+ */
2340
+ data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
2341
+ /**
2342
+ * Column configuration for the table.
2343
+ *
2344
+ * Defines how each column should be rendered, sorted, and styled.
2345
+ * Supports custom templates, sorting keys, and expandable columns.
2346
+ */
2347
+ columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
2348
+ /**
2349
+ * Pagination mode: 'none', 'pagination', or 'infinity'.
2350
+ *
2351
+ * - `none` - No pagination, all data is rendered
2352
+ * - `pagination` - Classic page-based pagination with fixed page size
2353
+ * - `infinity` - Infinite scroll mode, loads more data as user scrolls
2354
+ */
2355
+ mode = input(this.defaults.mode, ...(ngDevMode ? [{ debugName: "mode" }] : []));
2356
+ /**
2357
+ * Array of pinned rows that remain visible at the top or bottom.
2358
+ *
2359
+ * Pinned rows stay fixed while the rest of the content scrolls.
2360
+ * Useful for totals, summaries, or always-visible items.
2361
+ */
2362
+ pinnedRows = input([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
2363
+ /**
2364
+ * Function to determine if a row should become sticky at the top.
2365
+ *
2366
+ * When provided, rows matching this predicate will stick to the top
2367
+ * of the scroll area as the user scrolls.
2368
+ */
2369
+ isRowSticky = input(undefined, ...(ngDevMode ? [{ debugName: "isRowSticky" }] : []));
2370
+ isRowDisabled = input(undefined, ...(ngDevMode ? [{ debugName: "isRowDisabled" }] : []));
2371
+ /**
2372
+ * Function to choose a custom template for a row.
2373
+ *
2374
+ * If it returns a template, the row will be rendered with it;
2375
+ * otherwise, the default row rendering is used.
2376
+ */
2377
+ getRowTemplate = input(undefined, ...(ngDevMode ? [{ debugName: "getRowTemplate" }] : []));
2378
+ /**
2379
+ * Whether to add an index column showing row numbers.
2380
+ *
2381
+ * When enabled, it automatically adds a column displaying sequential row numbers.
2382
+ */
2383
+ hasIndexColumn = input(this.defaults.hasIndexColumn, { ...(ngDevMode ? { debugName: "hasIndexColumn" } : {}), transform: booleanAttribute });
2384
+ /**
2385
+ * Row selection configuration.
2386
+ *
2387
+ * Controls whether users can select rows and in what mode:
2388
+ * - `{ mode: 'none' }` - No selection
2389
+ * - `{ mode: 'single' }` - Single row selection
2390
+ * - `{ mode: 'multi' }` - Multiple row selection with checkboxes
2391
+ *
2392
+ * When selection is enabled, a `key` must be provided to identify rows.
2393
+ */
2394
+ selection = input(this.defaults.selection, ...(ngDevMode ? [{ debugName: "selection" }] : []));
2395
+ /**
2396
+ * Number of items per page.
2397
+ *
2398
+ * Used in pagination and infinity scroll modes to control
2399
+ * how many rows are loaded at once. Default is 20.
2400
+ */
2401
+ pageSize = input(this.defaults.pageSize, { ...(ngDevMode ? { debugName: "pageSize" } : {}), transform: numberAttribute });
2402
+ /**
2403
+ * Height of each row in pixels.
2404
+ *
2405
+ * Used for virtual scrolling calculations. Must be consistent
2406
+ * across all rows for accurate scrolling. Default is 40.
2407
+ */
2408
+ rowHeight = input(this.defaults.rowHeight, { ...(ngDevMode ? { debugName: "rowHeight" } : {}), transform: numberAttribute });
2409
+ /**
2410
+ * Grid height configuration.
2411
+ *
2412
+ * - `number` - Fixed height in pixels
2413
+ * - `'full'` - Fill container height (100%), can be managed by host component style
2414
+ * - `'default'` - Height by CSS var (--re-data-grid-height)
2415
+ */
2416
+ height = input(this.defaults.height, ...(ngDevMode ? [{ debugName: "height" }] : []));
2417
+ /**
2418
+ * Size of the virtual scroll buffer.
2419
+ *
2420
+ * Number of extra rows to render above and below the viewport
2421
+ * to reduce flickering during fast scrolling. Default is 8.
2422
+ */
2423
+ virtualBuffer = input(this.defaults.virtualBuffer, ...(ngDevMode ? [{ debugName: "virtualBuffer" }] : []));
2424
+ /**
2425
+ * Locks vertical scrolling while keeping horizontal scrolling enabled.
2426
+ *
2427
+ * Useful when the grid height is fixed by the parent and vertical scrolling
2428
+ * should be managed externally.
2429
+ */
2430
+ lockVerticalScroll = input(false, { ...(ngDevMode ? { debugName: "lockVerticalScroll" } : {}), transform: booleanAttribute });
2431
+ /**
2432
+ * Header group configuration for creating multi-level column headers.
2433
+ *
2434
+ * Allows grouping multiple columns under a common header label.
2435
+ * Each group spans from a starting column to an ending column and can have a custom alignment.
2436
+ *
2437
+ * @example
2438
+ * ```typescript
2439
+ * headerGroups = [
2440
+ * {
2441
+ * key: 'personal-info',
2442
+ * title: 'Personal Information',
2443
+ * from: 'name',
2444
+ * to: 'email',
2445
+ * align: 'center'
2446
+ * }
2447
+ * ];
2448
+ * ```
2449
+ */
2450
+ headerGroups = input([], ...(ngDevMode ? [{ debugName: "headerGroups" }] : []));
2451
+ /**
2452
+ * Loading state indicator.
2453
+ *
2454
+ * When true, displays loading template instead of data.
2455
+ * Useful during async data fetching operations.
2456
+ */
2457
+ loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : {}), transform: booleanAttribute });
2458
+ loadingMode = input(this.defaults.loadingMode, ...(ngDevMode ? [{ debugName: "loadingMode" }] : []));
2459
+ deferContent = input(this.defaults.deferContent, { ...(ngDevMode ? { debugName: "deferContent" } : {}), transform: booleanAttribute });
2460
+ deferHeader = input(this.defaults.deferHeader, { ...(ngDevMode ? { debugName: "deferHeader" } : {}), transform: booleanAttribute });
2461
+ deferPinned = input(this.defaults.deferPinned, { ...(ngDevMode ? { debugName: "deferPinned" } : {}), transform: booleanAttribute });
2462
+ deferCells = input(this.defaults.deferCells, { ...(ngDevMode ? { debugName: "deferCells" } : {}), transform: booleanAttribute });
2463
+ deferIcons = input(this.defaults.deferIcons, { ...(ngDevMode ? { debugName: "deferIcons" } : {}), transform: booleanAttribute });
2464
+ deferTooltip = input(this.defaults.deferTooltip, { ...(ngDevMode ? { debugName: "deferTooltip" } : {}), transform: booleanAttribute });
2465
+ /**
2466
+ * Function or property name for getting a unique row key.
2467
+ *
2468
+ * Used for efficient change detection and row tracking.
2469
+ * Can be a property name (string) or a function that returns a unique identifier.
2470
+ */
2471
+ rowKey = input(undefined, ...(ngDevMode ? [{ debugName: "rowKey" }] : []));
2472
+ /**
2473
+ * Whether to start a page count from 0 (true) or 1 (false).
2474
+ *
2475
+ * Controls the numbering scheme for pagination events.
2476
+ * Default is true (0-based indexing).
2477
+ */
2478
+ pageStartFromZero = input(this.defaults.pageStartFromZero, { ...(ngDevMode ? { debugName: "pageStartFromZero" } : {}), transform: booleanAttribute });
2479
+ sortMode = input(this.defaults.sortMode, ...(ngDevMode ? [{ debugName: "sortMode" }] : []));
2480
+ /**
2481
+ * Event emitted when requesting data for a new page.
2482
+ *
2483
+ * Fired in pagination and infinity scroll modes when the user navigates
2484
+ * to a different page or scrolls near the end of current data.
2485
+ *
2486
+ * @example
2487
+ * ```typescript
2488
+ * onPageChange(event: GridPageChangeEvent) {
2489
+ * this.loadData(event.page, event.rows);
2490
+ * }
2491
+ * ```
2492
+ */
2493
+ pageChange = output();
2494
+ /**
2495
+ * Event emitted when sort order changes.
2496
+ *
2497
+ * Fired when a user clicks on a sortable column header.
2498
+ * Contains the sort key and direction (asc/desc).
2499
+ *
2500
+ * @example
2501
+ * ```typescript
2502
+ * onSortChange(event: GridSortEvent<User>) {
2503
+ * this.data = sortBy(this.data, event.key, event.order);
2504
+ * }
2505
+ * ```
2506
+ */
2507
+ sortChange = output();
2508
+ multiSortChange = output();
2509
+ /**
2510
+ * Event emitted when selected rows change.
2511
+ *
2512
+ * Fired when a user selects or deselects rows.
2513
+ * Contains an array of currently selected row keys.
2514
+ */
2515
+ selectChange = output();
2516
+ /**
2517
+ * Event emitted when a row is clicked.
2518
+ *
2519
+ * Contains the clicked row data and its index.
2520
+ */
2521
+ rowClick = output();
2522
+ /**
2523
+ * Event emitted when a row is right-clicked (context menu).
2524
+ *
2525
+ * Contains the clicked row data, its index, and the native mouse event.
2526
+ */
2527
+ rowContext = output();
2528
+ /**
2529
+ * Event emitted when a row is double-clicked.
2530
+ *
2531
+ * Contains the clicked row data, its index, and the native mouse event.
2532
+ */
2533
+ rowDoubleClick = output();
2534
+ /**
2535
+ * Event emitted when a cell is clicked.
2536
+ *
2537
+ * Contains the clicked row, column configuration, and row index.
2538
+ */
2539
+ cellClick = output();
2540
+ /**
2541
+ * Event emitted when a cell is right-clicked (context menu).
2542
+ *
2543
+ * Contains the clicked row, column configuration, row index, and the native mouse event.
2544
+ */
2545
+ cellContext = output();
2546
+ /**
2547
+ * Event emitted when a cell is double-clicked.
2548
+ *
2549
+ * Contains the clicked row, column configuration, row index, and the native mouse event.
2550
+ */
2551
+ cellDoubleClick = output();
2552
+ vm = inject((DataGridVm));
2553
+ selector = new Selector();
2554
+ sortFeature = createGridSortFeature({
2555
+ getSortMode: () => this.sortMode(),
2556
+ getSortField: () => this.currentSortField,
2557
+ setSortField: (value) => (this.currentSortField = value),
2558
+ getSortOrder: () => this.currentSortOrder,
2559
+ setSortOrder: (value) => (this.currentSortOrder = value),
2560
+ getSorts: () => this.currentSorts,
2561
+ setSorts: (sorts) => this.setCurrentSorts(sorts),
2562
+ getSortOrderByKey: (key) => this.currentSortMap.get(key),
2563
+ emitSortChange: (event) => this.sortChange.emit(event),
2564
+ emitMultiSortChange: (sorts) => this.multiSortChange.emit({ sorts: [...sorts] }),
2565
+ });
2566
+ rowInteractionsFeature = createGridRowInteractionsFeature({
2567
+ isRowDisabled: (row, index) => this.isDisabledRow(row, index),
2568
+ getSelectionMode: () => this.selection().mode,
2569
+ selectRow: (row) => this.selector.select(row),
2570
+ emitSelectChange: (selected) => this.selectChange.emit({ selected }),
2571
+ emitCellClick: (payload) => this.cellClick.emit(payload),
2572
+ emitCellContext: (payload) => this.cellContext.emit(payload),
2573
+ emitCellDoubleClick: (payload) => this.cellDoubleClick.emit(payload),
2574
+ emitRowClick: (payload) => this.rowClick.emit(payload),
2575
+ emitRowContext: (payload) => this.rowContext.emit(payload),
2576
+ emitRowDoubleClick: (payload) => this.rowDoubleClick.emit(payload),
2577
+ });
2578
+ headerGroupsFeature = createGridHeaderGroupsFeature({
2579
+ getSortMode: () => this.sortMode(),
2580
+ getSingleSortField: () => this.currentSortField,
2581
+ getSingleSortOrder: () => this.currentSortOrder,
2582
+ getMultiSortMap: () => this.currentSortMap,
2583
+ getHeaderGroups: () => this.headerGroups(),
2584
+ setVmHeaderGroups: (groups) => this.vm.headerGroups.set(groups),
2585
+ });
2586
+ infinityPageRequestFeature = createGridInfinityPageRequestFeature({
2587
+ getPageSize: () => this.pageSize(),
2588
+ isPageStartFromZero: () => this.pageStartFromZero(),
2589
+ isLoading: () => this.loading(),
2590
+ emitPageChange: (event) => this.pageChange.emit(event),
2591
+ });
2592
+ expanderFeature = createGridExpanderFeature({
2593
+ runUntracked: (fn) => untracked(fn),
2594
+ getVmColumns: () => this.vm.columns(),
2595
+ setVmColumns: (columns) => this.vm.columns.set(columns),
2596
+ getExtendedColumns: () => this.extendedColumns(),
2597
+ getExpanderMap: () => this.expanderMap(),
2598
+ setExpanderMap: (map) => this.expanderMap.set(map),
2599
+ updateExpanderMap: (updater) => this.expanderMap.update(updater),
2600
+ });
2601
+ selectionReconcileFeature = createGridSelectionReconcileFeature({
2602
+ getSelection: () => this.selection(),
2603
+ getData: () => this.data() ?? [],
2604
+ getSelectedKeys: () => this.selector.selectedKeys(),
2605
+ setSelectedKeys: (keys) => this.selector.selectedKeys.set(keys),
2606
+ });
2607
+ gridApiFeature = createGridApiFeature({
2608
+ getSelectionFeature: () => this.selectionFeatureRef,
2609
+ getSelectionMode: () => this.selection().mode,
2610
+ clearSelectedKeys: () => this.selector.selectedKeys.set([]),
2611
+ selectAll: () => this.selector.selectAll(),
2612
+ emitSelectChange: (selected) => this.selectChange.emit({ selected }),
2613
+ loadSelectionFeature: () => this.loadSelectionFeature(),
2614
+ resetSort: () => this.sortFeature.resetSort(),
2615
+ setSort: (sort) => this.sortFeature.setSort(sort),
2616
+ setMultiSort: (sorts) => this.sortFeature.setMultiSort(sorts),
2617
+ });
2618
+ tooltipAdapterFeature = createGridTooltipAdapterFeature({
2619
+ getTooltipFeature: () => this.tooltipFeatureRef,
2620
+ loadTooltipFeature: () => this.loadTooltipFeature(),
2621
+ getTooltipElement: () => this.tooltipEl()?.nativeElement ?? null,
2622
+ });
2623
+ virtualScrollFeature = createGridVirtualScrollFeature({
2624
+ getScrollElement: () => this.scrollEl()?.nativeElement ?? null,
2625
+ getData: () => this.data() ?? [],
2626
+ getRowHeight: () => this.rowHeight(),
2627
+ getVirtualBuffer: () => this.virtualBuffer(),
2628
+ getPinnedTopCount: () => this.vm.pinnedTop().length,
2629
+ getMode: () => this.mode(),
2630
+ getPageSize: () => this.pageSize(),
2631
+ getRenderSlots: () => this.renderSlots(),
2632
+ setRenderSlots: (slots) => this.renderSlots.set(slots),
2633
+ getLastRange: () => ({ start: this.lastStartIndex, end: this.lastEndIndex }),
2634
+ setLastRange: ({ start, end }) => {
2635
+ this.lastStartIndex = start;
2636
+ this.lastEndIndex = end;
2637
+ },
2638
+ setStartIndex: (value) => (this.startIndex = value),
2639
+ setRenderCount: (value) => (this.renderCount = value),
2640
+ updateStickyRow: (scrollTop, rowHeight, pinnedTopH) => this.updateStickyRow(scrollTop, rowHeight, pinnedTopH),
2641
+ requestInfinityIfNeeded: (state) => this.infinityPageRequestFeature.requestIfNeeded(state),
2642
+ finalizeScroll: () => this.finalizeScroll(),
2643
+ });
2644
+ resizeObserverFeature = createGridResizeObserverFeature({
2645
+ getRootElement: () => this.rootEl()?.nativeElement ?? null,
2646
+ getResizeDebounceMs: () => this.defaults.debounce.resize,
2647
+ addSubscription: (subscription) => this.subscription.add(subscription),
2648
+ onWidthChanged: (width) => {
2649
+ this.vm.containerWidth.set(width);
2650
+ this.headerMeasureFeature.scheduleMeasure();
2651
+ },
2652
+ onHeightChanged: () => {
2653
+ this.onVerticalScroll();
2654
+ },
2655
+ });
2656
+ scrollLoopFeature = createGridScrollLoopFeature({
2657
+ getScrollElement: () => this.scrollEl()?.nativeElement ?? null,
2658
+ runOutsideAngular: (fn) => this.ngZone.runOutsideAngular(fn),
2659
+ runInAngular: (fn) => this.ngZone.run(fn),
2660
+ addSubscription: (subscription) => this.subscription.add(subscription),
2661
+ onVerticalScroll: () => this.onVerticalScroll(),
2662
+ onHorizontalScroll: () => this.onHorizontalScroll(),
2663
+ onStickySchedule: () => this.scheduleStickyUpdate(),
2664
+ hideTooltip: () => this.hideTooltip(),
2665
+ onInitialVerticalScroll: () => this.onVerticalScroll(true),
2666
+ });
2667
+ lifecycleInitFeature = createGridLifecycleInitFeature({
2668
+ registerAfterRenderEffect: (fn) => afterRenderEffect(fn),
2669
+ registerEffect: (fn) => effect(fn),
2670
+ registerOnDestroy: (fn) => inject(DestroyRef).onDestroy(fn),
2671
+ });
2672
+ stickyOrchestrationFeature = createGridStickyOrchestrationFeature({
2673
+ getData: () => this.data() ?? [],
2674
+ getStickyPredicate: () => this.isRowSticky(),
2675
+ setStickyIndexes: (indexes) => this.stickyIndexes.set(indexes),
2676
+ updateStickyFromScroll: () => this.updateStickyFromScroll(),
2677
+ ensureStickyFeatureLoaded: () => {
2678
+ void this.loadStickyFeature();
2679
+ },
2680
+ });
2681
+ headerMeasureFeature = createGridHeaderMeasureFeature({
2682
+ getHeaderElement: () => this.headerEl()?.nativeElement ?? null,
2683
+ setHeaderHeight: (height) => this.headerHeight.set(height),
2684
+ requestAnimationFrame: (cb) => requestAnimationFrame(cb),
2685
+ cancelAnimationFrame: (id) => cancelAnimationFrame(id),
2686
+ });
2687
+ selectionFeatureRef;
2688
+ selectionFeaturePromise;
2689
+ tooltipFeatureRef;
2690
+ tooltipFeaturePromise;
2691
+ overlayScrollFeatureRef;
2692
+ overlayScrollFeaturePromise;
2693
+ stickyFeatureRef;
2694
+ stickyFeaturePromise;
2695
+ rootEl = viewChild('root', ...(ngDevMode ? [{ debugName: "rootEl" }] : []));
2696
+ scrollEl = viewChild('scroll', ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
2697
+ headerEl = viewChild('header', ...(ngDevMode ? [{ debugName: "headerEl" }] : []));
2698
+ ngZone = inject(NgZone);
2699
+ cellTypedSlotRefs = contentChildren(DataGridTypeCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellTypedSlotRefs" }] : []));
2700
+ cellDataSlotRefs = contentChildren(DataGridCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellDataSlotRefs" }] : []));
2701
+ declarativeColumnRefs = contentChildren(DataGridDeclarativeColumn, ...(ngDevMode ? [{ debugName: "declarativeColumnRefs" }] : []));
2702
+ headerSlotRefs = contentChildren(DataGridHeaderTemplateDirective, ...(ngDevMode ? [{ debugName: "headerSlotRefs" }] : []));
2703
+ emptySlotRefs = contentChildren(DataGridCellEmptyDirective, ...(ngDevMode ? [{ debugName: "emptySlotRefs" }] : []));
2704
+ loadingSlotRefs = contentChildren(DataGridCellLoadingDirective, ...(ngDevMode ? [{ debugName: "loadingSlotRefs" }] : []));
2705
+ sortIcSlotRefs = contentChildren(DataGridSortIconDirective, ...(ngDevMode ? [{ debugName: "sortIcSlotRefs" }] : []));
2706
+ expanderIcSlotRefs = contentChildren(DataGridExpanderIconDirective, ...(ngDevMode ? [{ debugName: "expanderIcSlotRefs" }] : []));
2707
+ stickyRowSlotRefs = contentChildren(DataGridStickyRowDirective, ...(ngDevMode ? [{ debugName: "stickyRowSlotRefs" }] : []));
2708
+ rowSlotRefs = contentChildren(DataGridRowDirective, ...(ngDevMode ? [{ debugName: "rowSlotRefs" }] : []));
2709
+ emptyTpl = computed(() => this.emptySlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "emptyTpl" }] : []));
2710
+ loadingTpl = computed(() => this.loadingSlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "loadingTpl" }] : []));
2711
+ sortTpl = computed(() => this.sortIcSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "sortTpl" }] : []));
2712
+ expanderTpl = computed(() => this.expanderIcSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "expanderTpl" }] : []));
2713
+ stickyRowTpl = computed(() => this.stickyRowSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "stickyRowTpl" }] : []));
2714
+ rowTpl = computed(() => this.rowSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "rowTpl" }] : []));
2715
+ renderSlots = signal([], ...(ngDevMode ? [{ debugName: "renderSlots" }] : []));
2716
+ renderCount = 0;
2717
+ lastStartIndex = -1;
2718
+ lastEndIndex = -1;
2719
+ startIndex = 0;
2720
+ headerHeight = signal(this.defaults.headerHeight, ...(ngDevMode ? [{ debugName: "headerHeight" }] : []));
2721
+ tooltipEl = viewChild('tooltip', ...(ngDevMode ? [{ debugName: "tooltipEl" }] : []));
2722
+ tooltipState = signal({
2723
+ text: '',
2724
+ x: 0,
2725
+ y: 0,
2726
+ visible: false,
2727
+ }, ...(ngDevMode ? [{ debugName: "tooltipState" }] : []));
2728
+ stickyRowIndex = signal(null, ...(ngDevMode ? [{ debugName: "stickyRowIndex" }] : []));
2729
+ stickyRowTopPx = signal(0, ...(ngDevMode ? [{ debugName: "stickyRowTopPx" }] : []));
2730
+ stickyRowData = computed(() => {
2731
+ const index = this.stickyRowIndex();
2732
+ const rows = this.data();
2733
+ if (index === null || index < 0 || index >= rows.length) {
2734
+ return null;
2735
+ }
2736
+ return rows[index];
2737
+ }, ...(ngDevMode ? [{ debugName: "stickyRowData" }] : []));
2738
+ stickyIndexes = signal([], ...(ngDevMode ? [{ debugName: "stickyIndexes" }] : []));
2739
+ expanderMap = signal(new Map(), ...(ngDevMode ? [{ debugName: "expanderMap" }] : []));
2740
+ declarativeColumns = computed(() => normalizeDeclarativeColumns(this.declarativeColumnRefs().map((columnRef) => columnRef.toDeclarativeColumn()), this.rowKey()), ...(ngDevMode ? [{ debugName: "declarativeColumns" }] : []));
2741
+ sourceColumns = computed(() => mergeDeclarativeColumns(this.declarativeColumns().columns, this.columns()), ...(ngDevMode ? [{ debugName: "sourceColumns" }] : []));
2742
+ slotsFeature = createGridSlotsFeature({
2743
+ clearTypeTemplates: () => this.vm.globalTypeCellTpls.clear(),
2744
+ clearDataTemplates: () => this.vm.globalDataCellTpls.clear(),
2745
+ clearRowTemplates: () => this.vm.globalRowCellTpls.clear(),
2746
+ setTypeTemplate: (type, tpl) => this.vm.globalTypeCellTpls.set(type, tpl),
2747
+ setDataTemplate: (key, tpl) => this.vm.globalDataCellTpls.set(key, tpl),
2748
+ setRowTemplate: (key, tpl) => this.vm.globalRowCellTpls.set(key, tpl),
2749
+ getTypeTemplateRefs: () => this.cellTypedSlotRefs(),
2750
+ getDataTemplateRefs: () => this.cellDataSlotRefs(),
2751
+ getHeaderTemplateRefs: () => this.headerSlotRefs(),
2752
+ getRowTemplateEntries: () => this.declarativeColumns().rowCellTemplatesByKey.entries(),
2753
+ getExtendedColumns: () => this.extendedColumns(),
2754
+ });
2755
+ extendedColumns = computed(() => {
2756
+ const hasSelection = this.selection().mode !== 'none';
2757
+ const hasIndex = this.hasIndexColumn();
2758
+ const newColumns = [];
2759
+ hasSelection && newColumns.push(GRID_CHECKBOX_COLUMN);
2760
+ hasIndex && newColumns.push(GRID_INDEX_COLUMN);
2761
+ return [...newColumns, ...this.sourceColumns()];
2762
+ }, ...(ngDevMode ? [{ debugName: "extendedColumns" }] : []));
2763
+ /**
2764
+ * Computed CSS height value based on height setting.
2765
+ */
2766
+ styleHeight = computed(() => {
2767
+ const height = this.height();
2768
+ if (typeof height === 'number') {
2769
+ return `${height}px`;
2770
+ }
2771
+ else if (height === 'full') {
2772
+ return '100%';
2773
+ }
2774
+ return 'var(--re-data-grid-height)';
2775
+ }, ...(ngDevMode ? [{ debugName: "styleHeight" }] : []));
2776
+ hideSbTimeout;
2777
+ scrollbarRafId = null;
2778
+ stickyRafId = null;
2779
+ currentSortField;
2780
+ currentSortOrder = 'asc';
2781
+ currentSorts = [];
2782
+ currentSortMap = new Map();
2783
+ subscription = new Subscription();
2784
+ constructor() {
2785
+ this.lifecycleInitFeature.init({
2786
+ afterRender: [
2787
+ () => {
2788
+ this.initRefs();
2789
+ this.headerMeasureFeature.scheduleMeasure();
2790
+ this.initScroll();
2791
+ this.initObserver();
2792
+ },
2793
+ () => this.initSelector(),
2794
+ () => {
2795
+ this.initVm();
2796
+ this.initSort();
2797
+ this.initExpander();
2798
+ },
2799
+ ],
2800
+ effects: [
2801
+ () => {
2802
+ this.data();
2803
+ this.rowHeight();
2804
+ this.mode();
2805
+ this.onVerticalScroll(true);
2806
+ },
2807
+ () => {
2808
+ this.pinnedRows();
2809
+ this.vm.containerWidth();
2810
+ this.onVerticalScroll();
2811
+ },
2812
+ () => this.infinityPageRequestFeature.onDataTotalChanged(this.data()?.length ?? 0),
2813
+ () => {
2814
+ const selection = this.selection();
2815
+ if ('defaultSelected' in selection) {
2816
+ this.selector.selectedKeys.set(selection.defaultSelected || []);
2817
+ }
2818
+ if (selection.mode !== 'none') {
2819
+ void this.loadSelectionFeature();
2820
+ }
2821
+ },
2822
+ () => {
2823
+ this.selection();
2824
+ this.data();
2825
+ this.selectionReconcileFeature.reconcile();
2826
+ },
2827
+ () => {
2828
+ this.stickyOrchestrationFeature.reconcile();
2829
+ },
2830
+ () => {
2831
+ this.tooltipAdapterFeature.preloadForColumns(this.extendedColumns());
2832
+ },
2833
+ ],
2834
+ onDestroy: () => {
2835
+ this.subscription.unsubscribe();
2836
+ this.resizeObserverFeature.disconnect();
2837
+ this.infinityPageRequestFeature.reset();
2838
+ clearTimeout(this.hideSbTimeout);
2839
+ this.headerMeasureFeature.clearMeasure();
2840
+ this.clearScrollRaf();
2841
+ this.clearScrollbarRaf();
2842
+ this.clearStickyRaf();
2843
+ },
2844
+ });
2845
+ }
2846
+ /** Clears current selection and emits `selectChange`. */
2847
+ clearSelection() {
2848
+ this.gridApiFeature.clearSelection();
2849
+ }
2850
+ /** Selects all currently loaded rows (multi mode only) and emits `selectChange`. */
2851
+ selectAllLoaded() {
2852
+ this.gridApiFeature.selectAllLoaded();
2853
+ }
2854
+ /** Resets sorting state and emits sort events. */
2855
+ resetSort() {
2856
+ this.gridApiFeature.resetSort();
2857
+ }
2858
+ /** Sets a single-column sorting state and emits sort events. */
2859
+ setSort(sort) {
2860
+ this.gridApiFeature.setSort(sort);
2861
+ }
2862
+ /** Sets multi-column sorting state and emits sort events. */
2863
+ setMultiSort(sorts) {
2864
+ this.gridApiFeature.setMultiSort(sorts);
2865
+ }
2866
+ resolvePinnedData(pr) {
2867
+ return typeof pr.data === 'function' ? pr.data() : pr.data;
2868
+ }
2869
+ /**
2870
+ * Handles column header click for sorting.
2871
+ *
2872
+ * Toggles sort order between ascending and descending for the clicked column.
2873
+ * If a different column is clicked, it resets to ascending order.
2874
+ * Emits sortChange event with the current sort state.
2875
+ *
2876
+ * @param col - Column configuration that was clicked
2877
+ */
2878
+ onSort(col) {
2879
+ this.sortFeature.onSort(col.sortKey);
2880
+ }
2881
+ /**
2882
+ * Handles cell click events.
2883
+ *
2884
+ * Emits cellClick event and handles row selection if selection mode is enabled.
2885
+ * Updates the selection state and emits selectChange event accordingly.
2886
+ *
2887
+ * @param row - Data row that was clicked
2888
+ * @param col - Column configuration of the clicked cell
2889
+ * @param index - Row index in the dataset
2890
+ * @param event
2891
+ */
2892
+ onCellClick(row, col, index, event) {
2893
+ this.rowInteractionsFeature.onCellClick(row, col, index, event);
2894
+ }
2895
+ onSelectAll(event) {
2896
+ if (this.selectionFeatureRef) {
2897
+ this.selectionFeatureRef.onSelectAll(event);
2898
+ return;
2899
+ }
2900
+ event?.preventDefault();
2901
+ event?.stopPropagation();
2902
+ this.selectAllLoaded();
2903
+ void this.loadSelectionFeature();
2904
+ }
2905
+ onCheckboxToggle(row, index, event) {
2906
+ if (this.selectionFeatureRef) {
2907
+ this.selectionFeatureRef.onCheckboxToggle(row, index, event);
2908
+ return;
2909
+ }
2910
+ event?.preventDefault();
2911
+ event?.stopPropagation();
2912
+ if (this.isDisabledRow(row, index) || this.selection().mode === 'none') {
2913
+ return;
2914
+ }
2915
+ this.selectChange.emit({ selected: this.selector.select(row) });
2916
+ void this.loadSelectionFeature();
2917
+ }
2918
+ onSelectAllKeydown(event) {
2919
+ const key = event.key;
2920
+ if (key !== 'Enter' && key !== ' ') {
2921
+ return;
2922
+ }
2923
+ this.onSelectAll(event);
2924
+ }
2925
+ onCheckboxKeydown(row, index, event) {
2926
+ const key = event.key;
2927
+ if (key !== 'Enter' && key !== ' ') {
2928
+ return;
2929
+ }
2930
+ this.onCheckboxToggle(row, index, event);
2931
+ }
2932
+ onCellContext(row, col, index, event) {
2933
+ this.rowInteractionsFeature.onCellContext(row, col, index, event);
2934
+ }
2935
+ onCellDoubleClick(row, col, index, event) {
2936
+ this.rowInteractionsFeature.onCellDoubleClick(row, col, index, event);
2937
+ }
2938
+ onRowClick(row, index, event) {
2939
+ this.rowInteractionsFeature.onRowClick(row, index, event);
2940
+ }
2941
+ onRowContext(row, index, event) {
2942
+ this.rowInteractionsFeature.onRowContext(row, index, event);
2943
+ }
2944
+ onRowDoubleClick(row, index, event) {
2945
+ this.rowInteractionsFeature.onRowDoubleClick(row, index, event);
2946
+ }
2947
+ isExpandable(column) {
2948
+ return this.expanderFeature.isExpandable(column);
2949
+ }
2950
+ /**
2951
+ * Handles column expand/collapse toggle.
2952
+ *
2953
+ * Toggles the expanded state of a column and updates the visibility
2954
+ * of all dependent columns that reference this column via expandBy property.
2955
+ *
2956
+ * @param column - Column configuration to expand or collapse
2957
+ */
2958
+ onExpand(column) {
2959
+ this.expanderFeature.onExpand(column);
2960
+ }
2961
+ /**
2962
+ * Handles vertical scroll events and updates visible rows.
2963
+ *
2964
+ * Implements virtual scrolling by calculating which rows should be rendered
2965
+ * based on the current scroll position. Also handles infinite scroll data loading
2966
+ * when the user scrolls near the end of available data.
2967
+ *
2968
+ * @param initial - Whether this is the initial scroll calculation
2969
+ */
2970
+ onVerticalScroll(initial = false) {
2971
+ this.virtualScrollFeature.onVerticalScroll(initial);
2972
+ }
2973
+ onHorizontalScroll() { }
2974
+ /**
2975
+ * Handles mouse down event on scrollbar thumb for drag scrolling.
2976
+ *
2977
+ * Initiates dragging mode and sets up mouse move/up event listeners
2978
+ * to track thumb position and update scroll position accordingly.
2979
+ * Automatically cleans up listeners when dragging ends.
2980
+ *
2981
+ * @param e - Mouse down event from a scrollbar thumb element
2982
+ */
2983
+ onThumbDown(e) {
2984
+ if (this.overlayScrollFeatureRef) {
2985
+ this.overlayScrollFeatureRef.onThumbDown(e);
2986
+ return;
2987
+ }
2988
+ void this.loadOverlayScrollFeature().then((feature) => feature.onThumbDown(e));
2989
+ }
2990
+ showScrollbar() {
2991
+ if (this.overlayScrollFeatureRef) {
2992
+ this.overlayScrollFeatureRef.showScrollbar();
2993
+ return;
2994
+ }
2995
+ this.vm.scrollbarVisible.set(true);
2996
+ clearTimeout(this.hideSbTimeout);
2997
+ void this.loadOverlayScrollFeature();
2998
+ }
2999
+ hideScrollbarSoon(delay = 1200) {
3000
+ if (this.overlayScrollFeatureRef) {
3001
+ this.overlayScrollFeatureRef.hideScrollbarSoon(delay);
3002
+ return;
3003
+ }
3004
+ if (this.vm.dragging) {
3005
+ return;
3006
+ }
3007
+ clearTimeout(this.hideSbTimeout);
3008
+ this.hideSbTimeout = setTimeout(() => this.vm.scrollbarVisible.set(false), delay);
3009
+ void this.loadOverlayScrollFeature();
3010
+ }
3011
+ trackPinnedRow = (row) => row.order;
3012
+ isDisabledRow(row, index) {
3013
+ if (index < 0) {
3014
+ return false;
3015
+ }
3016
+ const predicate = this.isRowDisabled();
3017
+ return !!predicate && predicate(row, index);
3018
+ }
3019
+ cellClass(col, row) {
3020
+ if (typeof col.cellClass === 'function') {
3021
+ return col.cellClass(row);
3022
+ }
3023
+ return col.cellClass;
3024
+ }
3025
+ ariaSort(col) {
3026
+ return this.headerGroupsFeature.ariaSort(col);
3027
+ }
3028
+ sortOrderFor(col) {
3029
+ return this.headerGroupsFeature.sortOrderFor(col);
3030
+ }
3031
+ isActiveSort(col) {
3032
+ return this.headerGroupsFeature.isActiveSort(col);
3033
+ }
3034
+ showTooltip(event, row, col, index) {
3035
+ this.tooltipAdapterFeature.showTooltip(event, row, col, index);
3036
+ }
3037
+ hideTooltip() {
3038
+ this.tooltipAdapterFeature.hideTooltip();
3039
+ }
3040
+ isStickyRowIndex(index) {
3041
+ return this.stickyFeatureRef?.isStickyRowIndex(index) ?? false;
3042
+ }
3043
+ resolveRowTemplate(row, index) {
3044
+ const resolver = this.getRowTemplate();
3045
+ if (resolver) {
3046
+ const resolved = resolver(row, index);
3047
+ if (resolved) {
3048
+ return resolved;
3049
+ }
3050
+ }
3051
+ return this.rowTpl()?.tpl ?? null;
3052
+ }
3053
+ initVm() {
3054
+ this.vm.scrollEl.set(this.scrollEl());
3055
+ this.vm.columns.set(this.extendedColumns());
3056
+ this.vm.pinnedRows.set(this.pinnedRows());
3057
+ this.headerGroupsFeature.syncHeaderGroups();
3058
+ this.headerMeasureFeature.scheduleMeasure();
3059
+ }
3060
+ initSelector() {
3061
+ this.selector.data.set(this.data());
3062
+ this.selector.selection.set(this.selection());
3063
+ }
3064
+ initRefs() {
3065
+ this.slotsFeature.initRefs();
3066
+ }
3067
+ initSort() {
3068
+ if (this.sortMode() === 'single' && this.currentSorts.length > 1) {
3069
+ const [first] = this.currentSorts;
3070
+ this.setCurrentSorts([first]);
3071
+ this.currentSortField = `${first.key}`;
3072
+ this.currentSortOrder = first.order;
3073
+ return;
3074
+ }
3075
+ if (this.currentSorts.length > 0) {
3076
+ const [last] = this.currentSorts;
3077
+ this.currentSortField = `${last.key}`;
3078
+ this.currentSortOrder = last.order;
3079
+ return;
3080
+ }
3081
+ const firstSortable = this.extendedColumns()?.find((c) => !!c.sortKey);
3082
+ if (firstSortable) {
3083
+ this.currentSortField = firstSortable.sortKey;
3084
+ this.currentSortOrder = 'asc';
3085
+ this.setCurrentSorts([{ key: firstSortable.sortKey, order: 'asc' }]);
3086
+ }
3087
+ }
3088
+ initScroll() {
3089
+ void this.loadOverlayScrollFeature();
3090
+ this.scrollLoopFeature.initScroll();
3091
+ }
3092
+ initObserver() {
3093
+ this.resizeObserverFeature.initObserver();
3094
+ }
3095
+ initExpander() {
3096
+ this.expanderFeature.initExpander();
3097
+ }
3098
+ setCurrentSorts(sorts) {
3099
+ this.currentSorts = sorts;
3100
+ this.currentSortMap = new Map(sorts.map((item) => [String(item.key), item.order]));
3101
+ }
3102
+ loadSelectionFeature() {
3103
+ if (this.selectionFeatureRef) {
3104
+ return Promise.resolve(this.selectionFeatureRef);
3105
+ }
3106
+ if (this.selectionFeaturePromise) {
3107
+ return this.selectionFeaturePromise;
3108
+ }
3109
+ this.selectionFeaturePromise = import('./reforgium-data-grid-grid-selection.feature-CGRNpMeD.mjs').then(({ createGridSelectionFeature }) => {
3110
+ const feature = createGridSelectionFeature({
3111
+ getSelectionMode: () => this.selection().mode,
3112
+ clearSelectedKeys: () => this.selector.selectedKeys.set([]),
3113
+ selectAll: () => this.selector.selectAll(),
3114
+ selectRow: (row) => this.selector.select(row),
3115
+ emitSelectChange: (selected) => this.selectChange.emit({ selected }),
3116
+ isRowDisabled: (row, index) => this.isDisabledRow(row, index),
3117
+ });
3118
+ this.selectionFeatureRef = feature;
3119
+ return feature;
3120
+ });
3121
+ return this.selectionFeaturePromise;
3122
+ }
3123
+ loadTooltipFeature() {
3124
+ if (this.tooltipFeatureRef) {
3125
+ return Promise.resolve(this.tooltipFeatureRef);
3126
+ }
3127
+ if (this.tooltipFeaturePromise) {
3128
+ return this.tooltipFeaturePromise;
3129
+ }
3130
+ this.tooltipFeaturePromise = import('./reforgium-data-grid-grid-tooltip.feature-CMo88m8o.mjs').then(({ createGridTooltipFeature }) => {
3131
+ const feature = createGridTooltipFeature({
3132
+ getTooltipState: () => this.tooltipState(),
3133
+ setTooltipState: (state) => this.tooltipState.set(state),
3134
+ patchTooltipState: (patch) => this.tooltipState.update((prev) => ({ ...prev, ...patch })),
3135
+ requestPositioning: () => requestAnimationFrame(() => this.positionTooltip()),
3136
+ });
3137
+ this.tooltipFeatureRef = feature;
3138
+ return feature;
3139
+ });
3140
+ return this.tooltipFeaturePromise;
3141
+ }
3142
+ loadOverlayScrollFeature() {
3143
+ if (this.overlayScrollFeatureRef) {
3144
+ return Promise.resolve(this.overlayScrollFeatureRef);
3145
+ }
3146
+ if (this.overlayScrollFeaturePromise) {
3147
+ return this.overlayScrollFeaturePromise;
3148
+ }
3149
+ this.overlayScrollFeaturePromise = import('./reforgium-data-grid-grid-overlay-scroll.feature-DRUc6eDp.mjs').then(({ createGridOverlayScrollFeature }) => {
3150
+ const feature = createGridOverlayScrollFeature({
3151
+ getScrollElement: () => this.scrollEl()?.nativeElement ?? null,
3152
+ getThumbTop: () => this.vm.thumbTopPx(),
3153
+ setThumbTop: (value) => this.vm.thumbTopPx.set(value),
3154
+ calcScrollbar: () => this.vm.calcScrollbar(),
3155
+ isDragging: () => this.vm.dragging,
3156
+ setDragging: (value) => (this.vm.dragging = value),
3157
+ setScrollbarVisible: (value) => this.vm.scrollbarVisible.set(value),
3158
+ getHideTimeout: () => this.hideSbTimeout,
3159
+ setHideTimeout: (value) => (this.hideSbTimeout = value),
3160
+ getScrollbarRafId: () => this.scrollbarRafId,
3161
+ setScrollbarRafId: (value) => (this.scrollbarRafId = value),
3162
+ });
3163
+ this.overlayScrollFeatureRef = feature;
3164
+ return feature;
3165
+ });
3166
+ return this.overlayScrollFeaturePromise;
3167
+ }
3168
+ loadStickyFeature() {
3169
+ if (this.stickyFeatureRef) {
3170
+ return Promise.resolve(this.stickyFeatureRef);
3171
+ }
3172
+ if (this.stickyFeaturePromise) {
3173
+ return this.stickyFeaturePromise;
3174
+ }
3175
+ this.stickyFeaturePromise = import('./reforgium-data-grid-grid-sticky.feature-DBpn_6R8.mjs').then(({ createGridStickyFeature }) => {
3176
+ const feature = createGridStickyFeature({
3177
+ getStickyIndexes: () => this.stickyIndexes(),
3178
+ getStickyRowIndex: () => this.stickyRowIndex(),
3179
+ setStickyRowIndex: (value) => this.stickyRowIndex.set(value),
3180
+ setStickyRowTopPx: (value) => this.stickyRowTopPx.set(value),
3181
+ getHeaderHeight: () => this.headerHeight(),
3182
+ getStickyRafId: () => this.stickyRafId,
3183
+ setStickyRafId: (value) => (this.stickyRafId = value),
3184
+ runInAngular: (fn) => this.ngZone.run(fn),
3185
+ getScrollElement: () => this.scrollEl()?.nativeElement ?? null,
3186
+ getRowHeight: () => this.rowHeight(),
3187
+ getPinnedTopCount: () => this.vm.pinnedTop().length,
3188
+ });
3189
+ this.stickyFeatureRef = feature;
3190
+ return feature;
3191
+ });
3192
+ return this.stickyFeaturePromise;
3193
+ }
3194
+ positionTooltip() {
3195
+ this.tooltipAdapterFeature.positionTooltip();
3196
+ }
3197
+ scheduleScrollbarUpdate() {
3198
+ if (this.overlayScrollFeatureRef) {
3199
+ this.overlayScrollFeatureRef.scheduleScrollbarUpdate();
3200
+ return;
3201
+ }
3202
+ this.vm.calcScrollbar();
3203
+ void this.loadOverlayScrollFeature();
3204
+ }
3205
+ finalizeScroll() {
3206
+ if (this.overlayScrollFeatureRef) {
3207
+ this.overlayScrollFeatureRef.finalizeScroll();
3208
+ return;
3209
+ }
3210
+ this.scheduleScrollbarUpdate();
3211
+ this.showScrollbar();
3212
+ this.hideScrollbarSoon();
3213
+ }
3214
+ clearScrollRaf() {
3215
+ this.scrollLoopFeature.clearScrollRaf();
3216
+ }
3217
+ clearScrollbarRaf() {
3218
+ if (!this.overlayScrollFeatureRef) {
3219
+ return;
3220
+ }
3221
+ this.overlayScrollFeatureRef.clearScrollbarRaf();
3222
+ }
3223
+ scheduleStickyUpdate() {
3224
+ if (!this.isRowSticky()) {
3225
+ return;
3226
+ }
3227
+ if (this.stickyFeatureRef) {
3228
+ this.stickyFeatureRef.scheduleStickyUpdate();
3229
+ return;
3230
+ }
3231
+ void this.loadStickyFeature().then((feature) => feature.scheduleStickyUpdate());
3232
+ }
3233
+ clearStickyRaf() {
3234
+ if (!this.stickyFeatureRef) {
3235
+ return;
3236
+ }
3237
+ this.stickyFeatureRef.clearStickyRaf();
3238
+ }
3239
+ updateStickyRow(scrollTop, rowHeight, pinnedTopH) {
3240
+ if (!this.isRowSticky()) {
3241
+ this.stickyRowIndex.set(null);
3242
+ return;
3243
+ }
3244
+ if (this.stickyFeatureRef) {
3245
+ this.stickyFeatureRef.updateStickyRow(scrollTop, rowHeight, pinnedTopH);
3246
+ return;
3247
+ }
3248
+ void this.loadStickyFeature().then((feature) => feature.updateStickyRow(scrollTop, rowHeight, pinnedTopH));
3249
+ }
3250
+ updateStickyFromScroll() {
3251
+ if (!this.isRowSticky()) {
3252
+ this.stickyRowIndex.set(null);
3253
+ return;
3254
+ }
3255
+ if (this.stickyFeatureRef) {
3256
+ this.stickyFeatureRef.updateStickyFromScroll();
3257
+ return;
3258
+ }
3259
+ void this.loadStickyFeature().then((feature) => feature.updateStickyFromScroll());
3260
+ }
3261
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
3262
+ 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 }, isRowDisabled: { classPropertyName: "isRowDisabled", publicName: "isRowDisabled", 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 }, sortMode: { classPropertyName: "sortMode", publicName: "sortMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", sortChange: "sortChange", multiSortChange: "multiSortChange", 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 [attr.aria-multiselectable]=\"selection().mode === 'multi' ? true : null\"\r\n role=\"grid\"\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]=\"isActiveSort(col)\"\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\n aria-label=\"Select loaded rows\"\n [state]=\"selector.isAllSelected()\"\n tabindex=\"0\"\n (click)=\"onSelectAll($event)\"\n (keydown.enter)=\"onSelectAllKeydown($event)\"\n (keydown.space)=\"onSelectAllKeydown($event)\" />\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\n aria-label=\"Select loaded rows\"\n [state]=\"selector.isAllSelected()\"\n tabindex=\"0\"\n (click)=\"onSelectAll($event)\"\n (keydown.enter)=\"onSelectAllKeydown($event)\"\n (keydown.space)=\"onSelectAllKeydown($event)\" />\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 = sortOrderFor(col);\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\n aria-label=\"Toggle row selection\"\n [state]=\"selector.isSelected(row)\"\n [attr.aria-disabled]=\"isDisabledRow(row, index)\"\n [attr.tabindex]=\"isDisabledRow(row, index) ? -1 : 0\"\n (click)=\"onCheckboxToggle(row, index, $event)\"\n (keydown.enter)=\"onCheckboxKeydown(row, index, $event)\"\n (keydown.space)=\"onCheckboxKeydown(row, index, $event)\" />\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 [class.re-dg-row-disabled]=\"isDisabledRow(stickyRow, stickyIndex)\"\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.aria-disabled]=\"isDisabledRow(stickyRow, stickyIndex)\"\r\n [attr.aria-selected]=\"selection().mode !== 'none' ? selector.isSelected(stickyRow) : null\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"onRowClick(stickyRow, stickyIndex, $event)\"\r\n (contextmenu)=\"onRowContext(stickyRow, stickyIndex, $event)\"\r\n (dblclick)=\"onRowDoubleClick(stickyRow, stickyIndex, $event)\"\r\n (keydown.enter)=\"onRowClick(stickyRow, stickyIndex, $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=\"gridcell\"\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 [class.re-dg-row-disabled]=\"isDisabledRow(row, rowIndex)\"\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.aria-disabled]=\"isDisabledRow(row, rowIndex)\"\r\n [attr.aria-selected]=\"selection().mode !== 'none' ? selector.isSelected(row) : null\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"onRowClick(row, rowIndex, $event)\"\r\n (contextmenu)=\"onRowContext(row, rowIndex, $event)\"\r\n (dblclick)=\"onRowDoubleClick(row, rowIndex, $event)\"\r\n (keydown.enter)=\"onRowClick(row, rowIndex, $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=\"gridcell\"\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>\r\n @for (col of cols; track col.key) {\r\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\r\n @let isIndex = 'type' in col && col.type === 'index';\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 <div\r\n class=\"re-dg-cell\"\r\n role=\"gridcell\"\r\n [class.expanded]=\"!!col.expandBy\"\r\n [class]=\"cellClass(col, $any(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.height.px]=\"rowH\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [attr.tabindex]=\"isCheckbox || isIndex ? -1 : 0\"\r\n (mouseenter)=\"!isCheckbox && !isIndex && showTooltip($event, $any(row), col, -1)\"\r\n (mouseleave)=\"!isCheckbox && !isIndex && hideTooltip()\"\r\n (click)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event);\"\r\n (contextmenu)=\"!isCheckbox && !isIndex && onCellContext($any(row), col, -1, $event)\"\r\n (dblclick)=\"!isCheckbox && !isIndex && onCellDoubleClick($any(row), col, -1, $event)\"\r\n (keydown.enter)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event)\"\r\n >\r\n @if (!isCheckbox && !isIndex) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"dataCellContent\"\r\n [ngTemplateOutletContext]=\"{ $implicit: $any(row), col: col, index: -1 }\"\r\n />\r\n }\r\n </div>\r\n }\r\n </ng-template>\r\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-header-cell-line-height: 1.2;--re-data-grid-header-cell-max-lines: 2;--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-cell-line-height: 1.2;--re-data-grid-cell-max-lines: 2;--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);--re-data-grid-focus-ring-color: color-mix(in srgb, var(--primary-color, #2a90f4) 55%, transparent);--re-data-grid-focus-ring-width: 2px;--re-data-grid-focus-ring-offset: -2px;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:focus-visible,.re-dg-header-cell:focus-visible,.re-dg-header-cell button:focus-visible,.re-dg-row[tabindex=\"0\"]:focus-visible{outline:var(--re-data-grid-focus-ring-width) solid var(--re-data-grid-focus-ring-color);outline-offset:var(--re-data-grid-focus-ring-offset);z-index:4}.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.re-dg-row-disabled .re-dg-cell{opacity:.6;cursor:not-allowed}.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;overflow:hidden;text-overflow:ellipsis;white-space:normal;line-height:var(--re-data-grid-header-cell-line-height);-webkit-box-orient:vertical;-webkit-line-clamp:var(--re-data-grid-header-cell-max-lines)}.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]] });
3263
+ }
3264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGrid, decorators: [{
3265
+ type: Component,
3266
+ 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 [attr.aria-multiselectable]=\"selection().mode === 'multi' ? true : null\"\r\n role=\"grid\"\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]=\"isActiveSort(col)\"\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\n aria-label=\"Select loaded rows\"\n [state]=\"selector.isAllSelected()\"\n tabindex=\"0\"\n (click)=\"onSelectAll($event)\"\n (keydown.enter)=\"onSelectAllKeydown($event)\"\n (keydown.space)=\"onSelectAllKeydown($event)\" />\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\n aria-label=\"Select loaded rows\"\n [state]=\"selector.isAllSelected()\"\n tabindex=\"0\"\n (click)=\"onSelectAll($event)\"\n (keydown.enter)=\"onSelectAllKeydown($event)\"\n (keydown.space)=\"onSelectAllKeydown($event)\" />\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 = sortOrderFor(col);\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\n aria-label=\"Toggle row selection\"\n [state]=\"selector.isSelected(row)\"\n [attr.aria-disabled]=\"isDisabledRow(row, index)\"\n [attr.tabindex]=\"isDisabledRow(row, index) ? -1 : 0\"\n (click)=\"onCheckboxToggle(row, index, $event)\"\n (keydown.enter)=\"onCheckboxKeydown(row, index, $event)\"\n (keydown.space)=\"onCheckboxKeydown(row, index, $event)\" />\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 [class.re-dg-row-disabled]=\"isDisabledRow(stickyRow, stickyIndex)\"\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.aria-disabled]=\"isDisabledRow(stickyRow, stickyIndex)\"\r\n [attr.aria-selected]=\"selection().mode !== 'none' ? selector.isSelected(stickyRow) : null\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"onRowClick(stickyRow, stickyIndex, $event)\"\r\n (contextmenu)=\"onRowContext(stickyRow, stickyIndex, $event)\"\r\n (dblclick)=\"onRowDoubleClick(stickyRow, stickyIndex, $event)\"\r\n (keydown.enter)=\"onRowClick(stickyRow, stickyIndex, $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=\"gridcell\"\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 [class.re-dg-row-disabled]=\"isDisabledRow(row, rowIndex)\"\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.aria-disabled]=\"isDisabledRow(row, rowIndex)\"\r\n [attr.aria-selected]=\"selection().mode !== 'none' ? selector.isSelected(row) : null\"\r\n [attr.tabindex]=\"0\"\r\n (click)=\"onRowClick(row, rowIndex, $event)\"\r\n (contextmenu)=\"onRowContext(row, rowIndex, $event)\"\r\n (dblclick)=\"onRowDoubleClick(row, rowIndex, $event)\"\r\n (keydown.enter)=\"onRowClick(row, rowIndex, $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=\"gridcell\"\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>\r\n @for (col of cols; track col.key) {\r\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\r\n @let isIndex = 'type' in col && col.type === 'index';\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 <div\r\n class=\"re-dg-cell\"\r\n role=\"gridcell\"\r\n [class.expanded]=\"!!col.expandBy\"\r\n [class]=\"cellClass(col, $any(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.height.px]=\"rowH\"\r\n [style.width.px]=\"vm.widthByKey(col.key)\"\r\n [attr.tabindex]=\"isCheckbox || isIndex ? -1 : 0\"\r\n (mouseenter)=\"!isCheckbox && !isIndex && showTooltip($event, $any(row), col, -1)\"\r\n (mouseleave)=\"!isCheckbox && !isIndex && hideTooltip()\"\r\n (click)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event);\"\r\n (contextmenu)=\"!isCheckbox && !isIndex && onCellContext($any(row), col, -1, $event)\"\r\n (dblclick)=\"!isCheckbox && !isIndex && onCellDoubleClick($any(row), col, -1, $event)\"\r\n (keydown.enter)=\"!isCheckbox && !isIndex && onCellClick($any(row), col, -1, $event)\"\r\n >\r\n @if (!isCheckbox && !isIndex) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"dataCellContent\"\r\n [ngTemplateOutletContext]=\"{ $implicit: $any(row), col: col, index: -1 }\"\r\n />\r\n }\r\n </div>\r\n }\r\n </ng-template>\r\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-header-cell-line-height: 1.2;--re-data-grid-header-cell-max-lines: 2;--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-cell-line-height: 1.2;--re-data-grid-cell-max-lines: 2;--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);--re-data-grid-focus-ring-color: color-mix(in srgb, var(--primary-color, #2a90f4) 55%, transparent);--re-data-grid-focus-ring-width: 2px;--re-data-grid-focus-ring-offset: -2px;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:focus-visible,.re-dg-header-cell:focus-visible,.re-dg-header-cell button:focus-visible,.re-dg-row[tabindex=\"0\"]:focus-visible{outline:var(--re-data-grid-focus-ring-width) solid var(--re-data-grid-focus-ring-color);outline-offset:var(--re-data-grid-focus-ring-offset);z-index:4}.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.re-dg-row-disabled .re-dg-cell{opacity:.6;cursor:not-allowed}.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;overflow:hidden;text-overflow:ellipsis;white-space:normal;line-height:var(--re-data-grid-header-cell-line-height);-webkit-box-orient:vertical;-webkit-line-clamp:var(--re-data-grid-header-cell-max-lines)}.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"] }]
3267
+ }], 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 }] }], isRowDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isRowDisabled", 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 }] }], sortMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortMode", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], multiSortChange: [{ type: i0.Output, args: ["multiSortChange"] }], 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 }] }] } });
3268
+
3269
+ /**
3270
+ * Generated bundle index. Do not edit.
3271
+ */
3272
+
3273
+ export { DataGridTypeCellTemplateDirective as D, clampThumbTop as a, DataGridCellTemplateDirective as b, computeScrollbarState as c, DataGridHeaderTemplateDirective as d, DataGridRowDirective as e, DataGridDeclarativeColumn as f, DataGridDeclarativeHeaderDirective as g, DataGridDeclarativeCellDirective as h, DataGridCellEmptyDirective as i, DataGridCellLoadingDirective as j, DataGridStickyRowDirective as k, DataGridSortIconDirective as l, mapThumbTopToScrollTop as m, DataGridExpanderIconDirective as n, DATA_GRID_CONFIG as o, DEFAULT_DATA_GRID_DEFAULTS as p, provideDataGridDefaults as q, DataGrid as r };
3274
+ //# sourceMappingURL=reforgium-data-grid-reforgium-data-grid-Dn9s4YO5.mjs.map