@reforgium/data-grid 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,49 +1,247 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, inject, TemplateRef, Directive, signal, computed, effect, Injectable, Component, viewChild, ElementRef, ChangeDetectionStrategy, booleanAttribute, numberAttribute, output, contentChildren, afterRenderEffect, DestroyRef, untracked } from '@angular/core';
2
+ import { input, inject, TemplateRef, Directive, numberAttribute, output, computed, Component, signal, effect, Injectable, viewChild, ElementRef, ChangeDetectionStrategy, booleanAttribute, contentChildren, afterRenderEffect, DestroyRef, untracked } from '@angular/core';
3
3
  import { NgTemplateOutlet, DatePipe, DecimalPipe } from '@angular/common';
4
4
  import { Subscription, fromEvent, auditTime } from 'rxjs';
5
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 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
+ */
6
23
  class DataGridTypeCellTemplateDirective {
7
- type = input('', { ...(ngDevMode ? { debugName: "type" } : {}), alias: 'ssDataGridTypeCell' });
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
+ */
8
55
  tpl = inject((TemplateRef));
9
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridTypeCellTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
10
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.3", type: DataGridTypeCellTemplateDirective, isStandalone: true, selector: "ng-template[ssDataGridTypeCell]", inputs: { type: { classPropertyName: "type", publicName: "ssDataGridTypeCell", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
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 });
11
58
  }
12
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridTypeCellTemplateDirective, decorators: [{
59
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellTemplateDirective, decorators: [{
13
60
  type: Directive,
14
- args: [{ selector: 'ng-template[ssDataGridTypeCell]' }]
15
- }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "ssDataGridTypeCell", required: false }] }] } });
61
+ args: [{ selector: 'ng-template[reDataGridCell]' }]
62
+ }], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "reDataGridCell", required: false }] }] } });
16
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
+ */
17
78
  class DataGridHeaderTemplateDirective {
18
- key = input('', { ...(ngDevMode ? { debugName: "key" } : {}), alias: 'ssDataGridHeader' });
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
+ */
19
89
  tpl = inject((TemplateRef));
20
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridHeaderTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
21
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.3", type: DataGridHeaderTemplateDirective, isStandalone: true, selector: "ng-template[ssDataGridHeader]", inputs: { key: { classPropertyName: "key", publicName: "ssDataGridHeader", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
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 });
22
92
  }
23
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridHeaderTemplateDirective, decorators: [{
93
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridHeaderTemplateDirective, decorators: [{
24
94
  type: Directive,
25
- args: [{ selector: 'ng-template[ssDataGridHeader]' }]
26
- }], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "ssDataGridHeader", required: false }] }] } });
95
+ args: [{ selector: 'ng-template[reDataGridHeader]' }]
96
+ }], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "reDataGridHeader", required: false }] }] } });
27
97
 
98
+ /**
99
+ * Directive for providing a custom template to display when the data grid has no data.
100
+ *
101
+ * Used as a structural directive on `<ng-template>` elements within data grid components.
102
+ * The template receives a boolean context value indicating the empty state.
103
+ *
104
+ * Example:
105
+ * ```html
106
+ * <ng-template reDataGridEmpty let-isEmpty>
107
+ * <div *ngIf="isEmpty">No data available</div>
108
+ * </ng-template>
109
+ * ```
110
+ *
111
+ * Template context:
112
+ * - `$implicit: boolean` — indicates whether the grid is in an empty state
113
+ */
28
114
  class DataGridCellEmptyDirective {
29
115
  tpl = inject((TemplateRef));
30
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellEmptyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
31
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.3", type: DataGridCellEmptyDirective, isStandalone: true, selector: "ng-template[ssDataGridEmpty]", ngImport: i0 });
116
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellEmptyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
117
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridCellEmptyDirective, isStandalone: true, selector: "ng-template[reDataGridEmpty]", ngImport: i0 });
32
118
  }
33
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellEmptyDirective, decorators: [{
119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellEmptyDirective, decorators: [{
34
120
  type: Directive,
35
- args: [{ selector: 'ng-template[ssDataGridEmpty]' }]
121
+ args: [{ selector: 'ng-template[reDataGridEmpty]' }]
36
122
  }] });
123
+ /**
124
+ * Directive for providing a custom template to display when the data grid is loading data.
125
+ *
126
+ * Used as a structural directive on `<ng-template>` elements within data grid components.
127
+ * The template receives a boolean context value indicating the loading state.
128
+ *
129
+ * Example:
130
+ * ```html
131
+ * <ng-template reDataGridLoading let-isLoading>
132
+ * <div *ngIf="isLoading">Loading...</div>
133
+ * </ng-template>
134
+ * ```
135
+ *
136
+ * Template context:
137
+ * - `$implicit: boolean` — indicates whether the grid is in loading state
138
+ */
37
139
  class DataGridCellLoadingDirective {
38
140
  tpl = inject((TemplateRef));
39
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellLoadingDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
40
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.3", type: DataGridCellLoadingDirective, isStandalone: true, selector: "ng-template[ssDataGridLoading]", ngImport: i0 });
141
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellLoadingDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
142
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridCellLoadingDirective, isStandalone: true, selector: "ng-template[reDataGridLoading]", ngImport: i0 });
143
+ }
144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellLoadingDirective, decorators: [{
145
+ type: Directive,
146
+ args: [{ selector: 'ng-template[reDataGridLoading]' }]
147
+ }] });
148
+
149
+ class DataGridSortIconDirective {
150
+ tpl = inject((TemplateRef));
151
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridSortIconDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
152
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridSortIconDirective, isStandalone: true, selector: "ng-template[reDataGridSortIcon]", ngImport: i0 });
153
+ }
154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridSortIconDirective, decorators: [{
155
+ type: Directive,
156
+ args: [{ selector: 'ng-template[reDataGridSortIcon]' }]
157
+ }] });
158
+ class DataGridExpanderIconDirective {
159
+ tpl = inject((TemplateRef));
160
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridExpanderIconDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
161
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridExpanderIconDirective, isStandalone: true, selector: "ng-template[reDataGridExpanderIcon]", ngImport: i0 });
41
162
  }
42
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellLoadingDirective, decorators: [{
163
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridExpanderIconDirective, decorators: [{
43
164
  type: Directive,
44
- args: [{ selector: 'ng-template[ssDataGridLoading]' }]
165
+ args: [{ selector: 'ng-template[reDataGridExpanderIcon]' }]
45
166
  }] });
46
167
 
168
+ // noinspection CssUnresolvedCustomProperty
169
+ class DataGridPaginator {
170
+ current = input(0, { ...(ngDevMode ? { debugName: "current" } : {}), transform: numberAttribute });
171
+ totalElements = input(0, { ...(ngDevMode ? { debugName: "totalElements" } : {}), transform: numberAttribute });
172
+ pageSize = input(0, { ...(ngDevMode ? { debugName: "pageSize" } : {}), transform: numberAttribute });
173
+ maxShowPages = input(7, { ...(ngDevMode ? { debugName: "maxShowPages" } : {}), transform: numberAttribute });
174
+ pageChange = output();
175
+ totalPages = computed(() => {
176
+ const size = this.pageSize();
177
+ return size > 0 ? Math.ceil(this.totalElements() / size) : 0;
178
+ }, ...(ngDevMode ? [{ debugName: "totalPages" }] : []));
179
+ pages = computed(() => {
180
+ const current = this.current();
181
+ const total = this.totalPages();
182
+ const max = this.maxShowPages();
183
+ if (total <= max) {
184
+ return Array.from({ length: total }, (_, i) => i);
185
+ }
186
+ const pages = [];
187
+ const sidePages = Math.floor((max - 3) / 2);
188
+ pages.push(0);
189
+ let start = Math.max(1, current - sidePages);
190
+ let end = Math.min(total - 2, current + sidePages);
191
+ if (current <= sidePages + 1) {
192
+ end = max - 3;
193
+ }
194
+ else if (current >= total - sidePages - 2) {
195
+ start = total - max + 2;
196
+ }
197
+ if (start > 1) {
198
+ pages.push(-1);
199
+ }
200
+ for (let i = start; i <= end; i++) {
201
+ pages.push(i);
202
+ }
203
+ if (end < total - 2) {
204
+ pages.push(-1);
205
+ }
206
+ pages.push(total - 1);
207
+ return pages;
208
+ }, ...(ngDevMode ? [{ debugName: "pages" }] : []));
209
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridPaginator, deps: [], target: i0.ɵɵFactoryTarget.Component });
210
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DataGridPaginator, isStandalone: true, selector: "re-data-grid-paginator", inputs: { current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null }, totalElements: { classPropertyName: "totalElements", publicName: "totalElements", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, maxShowPages: { classPropertyName: "maxShowPages", publicName: "maxShowPages", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange" }, ngImport: i0, template: `
211
+ @for (page of pages(); track $index) {
212
+ @if (page === -1) {
213
+ <span class="re-paginator-gap">...</span>
214
+ } @else {
215
+ <button
216
+ class="re-paginator-page"
217
+ [class.re-paginator-page--active]="page === current()"
218
+ (click)="pageChange.emit(page)"
219
+ >
220
+ {{ page + 1 }}
221
+ </button>
222
+ }
223
+ }
224
+ `, isInline: true, styles: [":host{--re-data-grid-paginator-gap: .5rem;--re-data-grid-paginator-page-size: 1.75rem;--re-data-grid-paginator-page-border: 1px solid var(--re-data-grid-paginator-separator-color, #e2e8f0);--re-data-grid-paginator-page-separator-color: var(--re-data-grid-separator-color, --border-color);--re-data-grid-paginator-page-rounded: var(--re-data-grid-rounded, --radius-md);--re-data-grid-paginator-page-surface: var(--re-data-grid-surface, white);--re-data-grid-paginator-page-color: var(--text-primary, #1e293b);--re-data-grid-paginator-page-font-size: .875rem;--re-data-grid-paginator-page-active-surface: var(--re-data-grid-active, #3b82f6);--re-data-grid-paginator-page-active-color: white;--re-data-grid-paginator-page-hover-surface: var(--re-data-grid-active, #3b82f6);--re-data-grid-paginator-page-hover-color: white;display:flex;align-items:center;gap:var(--re-data-grid-paginator-gap)}.re-paginator-page{display:flex;justify-content:center;align-items:center;width:var(--re-data-grid-paginator-page-size);height:var(--re-data-grid-paginator-page-size);border-radius:var(--re-data-grid-paginator-page-rounded);border:var(--re-data-grid-paginator-page-border);font-size:var(--re-data-grid-paginator-page-font-size);background:var(--re-data-grid-paginator-page-surface);color:var(--re-data-grid-paginator-page-color);cursor:pointer;transition:all .2s}.re-paginator-page:hover:not(.re-paginator-page--active){background:var(--re-data-grid-paginator-page-hover-surface);color:var(--re-data-grid-paginator-page-hover-color)}.re-paginator-page--active{border-color:var(--re-data-grid-paginator-active-surface);background:var(--re-data-grid-paginator-page-active-surface);color:var(--re-data-grid-paginator-page-active-color)}.re-paginator-gap{display:flex;align-items:center;justify-content:center;padding:var(--re-data-grid-paginator-page-paddings);color:var(--re-data-grid-paginator-page-color)}\n"] });
225
+ }
226
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridPaginator, decorators: [{
227
+ type: Component,
228
+ args: [{ selector: 're-data-grid-paginator', template: `
229
+ @for (page of pages(); track $index) {
230
+ @if (page === -1) {
231
+ <span class="re-paginator-gap">...</span>
232
+ } @else {
233
+ <button
234
+ class="re-paginator-page"
235
+ [class.re-paginator-page--active]="page === current()"
236
+ (click)="pageChange.emit(page)"
237
+ >
238
+ {{ page + 1 }}
239
+ </button>
240
+ }
241
+ }
242
+ `, styles: [":host{--re-data-grid-paginator-gap: .5rem;--re-data-grid-paginator-page-size: 1.75rem;--re-data-grid-paginator-page-border: 1px solid var(--re-data-grid-paginator-separator-color, #e2e8f0);--re-data-grid-paginator-page-separator-color: var(--re-data-grid-separator-color, --border-color);--re-data-grid-paginator-page-rounded: var(--re-data-grid-rounded, --radius-md);--re-data-grid-paginator-page-surface: var(--re-data-grid-surface, white);--re-data-grid-paginator-page-color: var(--text-primary, #1e293b);--re-data-grid-paginator-page-font-size: .875rem;--re-data-grid-paginator-page-active-surface: var(--re-data-grid-active, #3b82f6);--re-data-grid-paginator-page-active-color: white;--re-data-grid-paginator-page-hover-surface: var(--re-data-grid-active, #3b82f6);--re-data-grid-paginator-page-hover-color: white;display:flex;align-items:center;gap:var(--re-data-grid-paginator-gap)}.re-paginator-page{display:flex;justify-content:center;align-items:center;width:var(--re-data-grid-paginator-page-size);height:var(--re-data-grid-paginator-page-size);border-radius:var(--re-data-grid-paginator-page-rounded);border:var(--re-data-grid-paginator-page-border);font-size:var(--re-data-grid-paginator-page-font-size);background:var(--re-data-grid-paginator-page-surface);color:var(--re-data-grid-paginator-page-color);cursor:pointer;transition:all .2s}.re-paginator-page:hover:not(.re-paginator-page--active){background:var(--re-data-grid-paginator-page-hover-surface);color:var(--re-data-grid-paginator-page-hover-color)}.re-paginator-page--active{border-color:var(--re-data-grid-paginator-active-surface);background:var(--re-data-grid-paginator-page-active-surface);color:var(--re-data-grid-paginator-page-active-color)}.re-paginator-gap{display:flex;align-items:center;justify-content:center;padding:var(--re-data-grid-paginator-page-paddings);color:var(--re-data-grid-paginator-page-color)}\n"] }]
243
+ }], propDecorators: { current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }], totalElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalElements", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], maxShowPages: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxShowPages", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }] } });
244
+
47
245
  const GRID_INDEX_COLUMN = {
48
246
  key: '_index',
49
247
  type: 'index',
@@ -61,6 +259,38 @@ const GRID_CHECKBOX_COLUMN = {
61
259
  sticky: true,
62
260
  };
63
261
 
262
+ /**
263
+ * Calculates and distributes column widths within a container based on column configuration.
264
+ *
265
+ * The function implements a flexible layout algorithm that:
266
+ * - Respects fixed-width columns (with `width` property set)
267
+ * - Distributes remaining space among auto-sized columns based on their `flex` ratios
268
+ * - Enforces `minWidth` and `maxWidth` constraints
269
+ * - Uses a "water-fill" algorithm to grow columns proportionally
270
+ * - Handles rounding errors to ensure total width matches container width
271
+ *
272
+ * @param columns - Array of column configuration objects with properties
273
+ * like `visible`, `width`, `minWidth`, `maxWidth`, `flex`, and `key`
274
+ * @param containerWidth - Available width in pixels for all columns
275
+ * @param defaultCol - Default minimum width for auto-sized columns without explicit `minWidth`
276
+ * @returns Layout result containing computed widths array, total width, and width lookup by column key
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * const result = layoutColumns(
281
+ * [
282
+ * { key: 'id', width: 50, visible: true },
283
+ * { key: 'name', minWidth: 100, flex: 2, visible: true },
284
+ * { key: 'age', minWidth: 80, flex: 1, visible: true }
285
+ * ],
286
+ * 800,
287
+ * 100
288
+ * );
289
+ * // result.widths = [50, 500, 250]
290
+ * // result.total = 800
291
+ * // result.byKey = { id: 50, name: 500, age: 250 }
292
+ * ```
293
+ */
64
294
  function layoutColumns(columns, containerWidth, defaultCol) {
65
295
  const idx = visibleIndexes(columns);
66
296
  const { fixedIdx, autoIdx } = splitFixed(columns, idx);
@@ -94,6 +324,14 @@ function layoutColumns(columns, containerWidth, defaultCol) {
94
324
  }
95
325
  return { widths, total, byKey };
96
326
  }
327
+ /**
328
+ * Filters and returns indexes of visible columns.
329
+ *
330
+ * A column is considered visible if its `visible` property is not explicitly set to `false`.
331
+ *
332
+ * @param cols - Array of column configurations
333
+ * @returns Array of indexes for columns that should be displayed
334
+ */
97
335
  function visibleIndexes(cols) {
98
336
  const out = [];
99
337
  for (let i = 0; i < cols.length; i++) {
@@ -102,6 +340,16 @@ function visibleIndexes(cols) {
102
340
  }
103
341
  return out;
104
342
  }
343
+ /**
344
+ * Splits visible column indexes into fixed-width and auto-sized groups.
345
+ *
346
+ * Fixed columns have an explicit `width` property defined.
347
+ * Auto-sized columns have `width` as `undefined` and will grow to fill available space.
348
+ *
349
+ * @param cols - Array of column configurations
350
+ * @param visibleIdx - Array of visible column indexes
351
+ * @returns Object with `fixedIdx` (fixed-width column indexes) and `autoIdx` (auto-sized column indexes)
352
+ */
105
353
  function splitFixed(cols, visibleIdx) {
106
354
  const fixedIdx = [];
107
355
  const autoIdx = [];
@@ -110,16 +358,53 @@ function splitFixed(cols, visibleIdx) {
110
358
  }
111
359
  return { fixedIdx, autoIdx };
112
360
  }
361
+ /**
362
+ * Computes actual widths for fixed-width columns, respecting min/max constraints.
363
+ *
364
+ * Takes the explicit `width` value and clamps it between `minWidth` and `maxWidth`.
365
+ *
366
+ * @param cols - Array of column configurations
367
+ * @param fixedIdx - Array of fixed-width column indexes
368
+ * @returns Array of objects with column index and computed width
369
+ */
113
370
  const computeFixedWidths = (cols, fixedIdx) => fixedIdx.map((index) => {
114
371
  const col = cols[index];
115
372
  const width = clamp$1(col.width, col.minWidth, col.maxWidth);
116
373
  return { index, width };
117
374
  });
375
+ /**
376
+ * Computes base (minimum) widths for auto-sized columns before distribution of free space.
377
+ *
378
+ * Uses column's `minWidth` if specified, otherwise falls back to the default value.
379
+ * The base width is clamped between `minWidth` and `maxWidth` constraints.
380
+ *
381
+ * @param cols - Array of column configurations
382
+ * @param autoIdx - Array of auto-sized column indexes
383
+ * @param def - Default minimum width to use when column's `minWidth` is not specified
384
+ * @returns Array of objects with column index and base width
385
+ */
118
386
  const computeBaseAuto = (cols, autoIdx, def) => autoIdx.map((index) => {
119
387
  const c = cols[index];
120
388
  const base = clamp$1(c.minWidth ?? def, c.minWidth, c.maxWidth);
121
389
  return { index, width: base };
122
390
  });
391
+ /**
392
+ * Distributes free space among auto-sized columns using a "water-fill" algorithm.
393
+ *
394
+ * The algorithm works iteratively:
395
+ * 1. Identifies columns that can still grow (haven't reached `maxWidth`)
396
+ * 2. Distributes remaining space proportionally based on each column's `flex` ratio
397
+ * 3. Respects `maxWidth` constraints by capping growth
398
+ * 4. Repeats until no space remains or no columns can grow further
399
+ *
400
+ * This ensures that columns with higher `flex` values receive proportionally more space,
401
+ * while respecting all width constraints.
402
+ *
403
+ * @param cols - Array of column configurations
404
+ * @param base - Array of column indexes with their base widths before distribution
405
+ * @param free - Amount of free space (in pixels) to distribute among columns
406
+ * @returns Array of objects with column index and final width after distribution
407
+ */
123
408
  function distributeFree(cols, base, free) {
124
409
  if (free <= 0 || base.length === 0) {
125
410
  return base;
@@ -151,10 +436,37 @@ function distributeFree(cols, base, free) {
151
436
  }
152
437
  return widths;
153
438
  }
439
+ /**
440
+ * Checks whether a column can grow beyond its current width.
441
+ *
442
+ * A column can grow if its current width is less than its `maxWidth` constraint
443
+ * (or `Infinity` if no max is specified), with a small epsilon tolerance.
444
+ *
445
+ * @param cols - Array of column configurations
446
+ * @param i - Column index to check
447
+ * @param cur - Current width of the column
448
+ * @returns `true` if the column can grow, `false` otherwise
449
+ */
154
450
  function widthsCanGrow(cols, i, cur) {
155
451
  const max = cols[i].maxWidth ?? Infinity;
156
452
  return cur < max - 1e-6;
157
453
  }
454
+ /**
455
+ * Rounds auto-sized column widths to integers and distributes any remaining pixels to match container width exactly.
456
+ *
457
+ * This function handles rounding errors that occur when distributing fractional widths:
458
+ * 1. Floors all auto-sized column widths to integers
459
+ * 2. Calculates how many pixels are needed to reach the exact container width
460
+ * 3. Distributes remaining pixels one-by-one to columns (right-to-left) that haven't reached their `maxWidth`
461
+ *
462
+ * Fixed-width columns are not modified. This ensures the total width matches the container precisely.
463
+ *
464
+ * @param cols - Array of column configurations
465
+ * @param widths - Array of column widths to be modified in place
466
+ * @param fixedIdx - Array of fixed-width column indexes (not modified)
467
+ * @param autoIdx - Array of auto-sized column indexes (will be rounded and adjusted)
468
+ * @param containerWidth - Target total width that must be matched exactly
469
+ */
158
470
  function roundAndFix(cols, widths, fixedIdx, autoIdx, containerWidth) {
159
471
  const sumFixed = fixedIdx.reduce((s, i) => s + widths[i], 0);
160
472
  let sumAuto = 0;
@@ -175,11 +487,33 @@ function roundAndFix(cols, widths, fixedIdx, autoIdx, containerWidth) {
175
487
  }
176
488
  }
177
489
  }
490
+ /**
491
+ * Clamps a numeric value between optional minimum and maximum bounds.
492
+ *
493
+ * If `min` is provided and the value is less than it, returns `min`.
494
+ * If `max` is provided and the value is greater than it, returns `max`.
495
+ * Otherwise returns the original value.
496
+ *
497
+ * @param v - Value to clamp
498
+ * @param min - Optional minimum bound
499
+ * @param max - Optional maximum bound
500
+ * @returns Clamped value
501
+ */
178
502
  function clamp$1(v, min, max) {
179
503
  min != null && v < min && (v = min);
180
504
  max != null && v > max && (v = max);
181
505
  return v;
182
506
  }
507
+ /**
508
+ * Calculates the sum of numeric values or width properties in an array.
509
+ *
510
+ * Supports two input formats:
511
+ * - Array of numbers: sums all numeric values
512
+ * - Array of objects with `width` property: sums all `width` values
513
+ *
514
+ * @param items - Array of numbers or objects with `width` property
515
+ * @returns Sum of all values
516
+ */
183
517
  function sum(items) {
184
518
  if (Array.isArray(items) && typeof items[0] === 'number') {
185
519
  return items.reduce((s, x) => s + x, 0);
@@ -188,8 +522,8 @@ function sum(items) {
188
522
  }
189
523
 
190
524
  /**
191
- * Вычисляет визуальное состояние оверлейного скроллбара. Все аргументы - сырые DOM-числа.
192
- * Возвращает состояние, описывающее видимость, размер и позицию ползунка.
525
+ * Calculates the visual state of an overlay scrollbar. All arguments are raw DOM numbers.
526
+ * Returns a state describing the visibility, size, and position of the thumb.
193
527
  */
194
528
  function computeScrollbarState(scrollHeight = 0, clientHeight = 0, scrollTop = 0, minThumb = 24) {
195
529
  const safeClient = toSafe(clientHeight);
@@ -217,14 +551,14 @@ function computeScrollbarState(scrollHeight = 0, clientHeight = 0, scrollTop = 0
217
551
  maxScrollTop,
218
552
  };
219
553
  }
220
- /** Преобразует позицию ползунка thumbTop (0..maxThumbTop) в позицию прокрутки scrollTop (0..maxScrollTop) */
554
+ /** Converts thumb position thumbTop (0..maxThumbTop) to scroll position scrollTop (0..maxScrollTop) */
221
555
  function mapThumbTopToScrollTop(thumbTop, maxThumbTop, maxScrollTop) {
222
556
  const mt = Math.max(1, toSafe(maxThumbTop));
223
557
  const ms = Math.max(1, toSafe(maxScrollTop));
224
558
  const tt = clamp(toSafe(thumbTop), 0, mt);
225
559
  return (tt / mt) * ms;
226
560
  }
227
- /** Ограничивает новую позицию ползунка в пределах 0..maxThumbTop */
561
+ /** Clamps the new thumb position within the bounds 0..maxThumbTop */
228
562
  function clampThumbTop(value, maxThumbTop) {
229
563
  const mt = Math.max(1, toSafe(maxThumbTop));
230
564
  return clamp(toSafe(value), 0, mt);
@@ -243,22 +577,68 @@ function toSafe(n) {
243
577
  return Number.isFinite(n) ? n : 0;
244
578
  }
245
579
  function clamp(v, min, max) {
246
- if (v < min)
580
+ if (v < min) {
247
581
  return min;
248
- if (v > max)
582
+ }
583
+ if (v > max) {
249
584
  return max;
585
+ }
250
586
  return v;
251
587
  }
252
588
 
589
+ /**
590
+ * Detects the primary scroll direction of an HTML element.
591
+ *
592
+ * Compares the current scroll position with the previous one to determine
593
+ * whether the user is scrolling horizontally, vertically, or not at all.
594
+ *
595
+ * Example:
596
+ * ```typescript
597
+ * const detector = new ScrollDirectionDetector(scrollableDiv);
598
+ *
599
+ * scrollableDiv.addEventListener('scroll', () => {
600
+ * const direction = detector.detect();
601
+ * console.log('Scroll direction:', direction); // 'horizontal' | 'vertical' | 'none'
602
+ * });
603
+ * ```
604
+ *
605
+ * The detector stores the previous scroll position internally and updates it
606
+ * on each `detect()` call to track movement deltas.
607
+ */
253
608
  class ScrollDirectionDetector {
254
609
  el;
610
+ /**
611
+ * Previously recorded vertical scroll position (scrollTop).
612
+ * @private
613
+ */
255
614
  #prevTop = 0;
615
+ /**
616
+ * Previously recorded horizontal scroll position (scrollLeft).
617
+ * @private
618
+ */
256
619
  #prevLeft = 0;
620
+ /**
621
+ * Creates a new scroll direction detector for the given HTML element.
622
+ *
623
+ * @param el - The HTML element whose scroll direction will be tracked.
624
+ * The element must be scrollable (have overflow content).
625
+ */
257
626
  constructor(el) {
258
627
  this.el = el;
259
628
  this.#prevTop = el.scrollTop;
260
629
  this.#prevLeft = el.scrollLeft;
261
630
  }
631
+ /**
632
+ * Detects the primary scroll direction based on position changes since the last call.
633
+ *
634
+ * Compares the absolute deltas of horizontal and vertical scroll positions.
635
+ * The direction with the greater delta is considered the primary scroll direction.
636
+ *
637
+ * @returns The detected scroll direction:
638
+ * - `'horizontal'` if horizontal movement is greater
639
+ * - `'vertical'` if vertical movement is greater
640
+ * - `'none'` if no scroll movement occurred or deltas are equal
641
+ */
262
642
  detect() {
263
643
  const { scrollTop, scrollLeft } = this.el;
264
644
  const deltaX = Math.abs(scrollLeft - this.#prevLeft);
@@ -275,6 +655,26 @@ class ScrollDirectionDetector {
275
655
  }
276
656
  }
277
657
 
658
+ /**
659
+ * Splits an array of grid columns into sticky left, sticky right, and all visible columns.
660
+ *
661
+ * This function filters columns by visibility, then divides them at the midpoint
662
+ * to identify which sticky columns should be pinned to the left versus right side
663
+ * of the data grid.
664
+ *
665
+ * @template Data - The data type extending `AnyDict` that the grid columns are based on.
666
+ * @param cols - Array of grid columns to be split.
667
+ * @returns An object containing:
668
+ * - `left`: Array of sticky columns from the first half of visible columns.
669
+ * - `right`: Array of sticky columns from the second half of visible columns.
670
+ * - `visible`: Array of all visible columns (filtered by `visible !== false`).
671
+ *
672
+ * @example
673
+ * ```typescript
674
+ * const columns: GridColumn<User>[] = [...];
675
+ * const { left, right, visible } = splitSticky(columns);
676
+ * ```
677
+ */
278
678
  function splitSticky(cols) {
279
679
  const visible = cols.filter((c) => c.visible !== false);
280
680
  const middleIndex = Math.floor(visible.length / 2);
@@ -283,20 +683,93 @@ function splitSticky(cols) {
283
683
  return { left, right, visible };
284
684
  }
285
685
 
686
+ /**
687
+ * View model for the data grid component.
688
+ *
689
+ * Manages grid state including column layout, sticky positioning, scrollbar calculations,
690
+ * and pinned rows. Automatically recomputes column widths based on container size and
691
+ * handles sticky column offsets for left and right pinned columns.
692
+ *
693
+ * @template Data - Type of data objects in the grid, must extend AnyDict
694
+ *
695
+ * @example
696
+ * ```typescript
697
+ * const gridVm = inject(DataGridVm<MyDataType>);
698
+ * gridVm.columns.set([{ key: 'name', title: 'Name' }]);
699
+ * gridVm.containerWidth.set(800);
700
+ * ```
701
+ */
286
702
  class DataGridVm {
703
+ /**
704
+ * Reference to the scrollable container element.
705
+ *
706
+ * Used for scrollbar calculations and scroll position management.
707
+ */
287
708
  scrollEl = signal(undefined, ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
709
+ /**
710
+ * Array of column configurations for the grid.
711
+ *
712
+ * Defines all columns including their keys, titles, sticky positioning, and widths.
713
+ * Value is reactive and triggers column layout recalculation when changed.
714
+ */
288
715
  columns = signal([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
716
+ /**
717
+ * Array of pinned row configurations.
718
+ *
719
+ * Defines rows that remain fixed at the top or bottom of the grid during scrolling.
720
+ * Each row includes data, position ('top' or 'bottom'), and optional ordering.
721
+ */
289
722
  pinnedRows = signal([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
723
+ /**
724
+ * Current width of the grid container in pixels.
725
+ *
726
+ * Used for column width calculations and layout adjustments.
727
+ * Value is reactive and triggers column layout recalculation when changed.
728
+ */
290
729
  containerWidth = signal(0, ...(ngDevMode ? [{ debugName: "containerWidth" }] : []));
730
+ /**
731
+ * Flag indicating whether the custom scrollbar should be visible.
732
+ *
733
+ * Automatically computed based on content height vs. container height.
734
+ */
291
735
  scrollbarVisible = signal(false, ...(ngDevMode ? [{ debugName: "scrollbarVisible" }] : []));
736
+ /**
737
+ * Height of the scrollbar thumb in pixels.
738
+ *
739
+ * Proportional to the ratio of visible content to total content height.
740
+ */
292
741
  thumbHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbHeightPx" }] : []));
742
+ /**
743
+ * Top position of the scrollbar thumb in pixels.
744
+ *
745
+ * Corresponds to the current scroll position within the scrollable area.
746
+ */
293
747
  thumbTopPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbTopPx" }] : []));
748
+ /**
749
+ * Flag indicating whether the user is currently dragging the scrollbar thumb.
750
+ *
751
+ * Used to track active scroll drag interactions.
752
+ */
294
753
  dragging = false;
754
+ /**
755
+ * Map of global cell renderer templates by type.
756
+ *
757
+ * Stores reusable template references for different cell renderer types
758
+ * that can be shared across multiple columns.
759
+ */
295
760
  globalTypeCellTpls = new Map();
761
+ globalDataCellTpls = new Map();
296
762
  #byKey = signal({}, ...(ngDevMode ? [{ debugName: "#byKey" }] : []));
297
763
  #defaultColWidth = 140;
298
764
  #stickyLeftMap = new Map();
299
765
  #stickyRightMap = new Map();
766
+ /**
767
+ * Computed an array of non-sticky columns to display in the scrollable area.
768
+ *
769
+ * Automatically splits columns into left-sticky, visible, and right-sticky groups,
770
+ * recomputes sticky offsets, and returns only the scrollable middle section.
771
+ * Recalculates whenever columns or container width changes.
772
+ */
300
773
  columnsToShow = computed(() => {
301
774
  this.containerWidth();
302
775
  const cols = this.columns() ?? [];
@@ -304,7 +777,19 @@ class DataGridVm {
304
777
  this.recomputeStickyOffsets(left, right);
305
778
  return visible;
306
779
  }, ...(ngDevMode ? [{ debugName: "columnsToShow" }] : []));
780
+ /**
781
+ * Computed array of rows pinned to the top of the grid.
782
+ *
783
+ * Filters pinned rows by 'top' position and sorts them by order property.
784
+ * Rows with lower order values appear first.
785
+ */
307
786
  pinnedTop = computed(() => (this.pinnedRows() ?? []).filter((r) => r.position === 'top').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)), ...(ngDevMode ? [{ debugName: "pinnedTop" }] : []));
787
+ /**
788
+ * Computed array of rows pinned to the bottom of the grid.
789
+ *
790
+ * Filters pinned rows by 'bottom' position and sorts them by order property.
791
+ * Rows with lower order values appear first.
792
+ */
308
793
  pinnedBottom = computed(() => (this.pinnedRows() ?? []).filter((r) => r.position === 'bottom').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)), ...(ngDevMode ? [{ debugName: "pinnedBottom" }] : []));
309
794
  constructor() {
310
795
  effect(() => {
@@ -317,14 +802,51 @@ class DataGridVm {
317
802
  this.#byKey.set(res.byKey);
318
803
  });
319
804
  }
805
+ /**
806
+ * Returns the computed width for a column by its key.
807
+ *
808
+ * If the column width has not been calculated, returns the default column width.
809
+ *
810
+ * @param key - The unique identifier for the column
811
+ * @returns Width in pixels
812
+ */
320
813
  widthByKey = (key) => this.#byKey()[key] ?? this.#defaultColWidth;
814
+ /**
815
+ * Checks if a column is pinned to the left side of the grid.
816
+ *
817
+ * @param key - The unique identifier for the column
818
+ * @returns `true` if the column is sticky on the left, `false` otherwise
819
+ */
321
820
  isStickyLeft = (key) => this.#stickyLeftMap.has(key);
821
+ /**
822
+ * Checks if a column is pinned to the right side of the grid.
823
+ *
824
+ * @param key - The unique identifier for the column
825
+ * @returns `true` if the column is sticky on the right, `false` otherwise
826
+ */
322
827
  isStickyRight = (key) => this.#stickyRightMap.has(key);
828
+ /**
829
+ * Returns the horizontal offset for a sticky column.
830
+ *
831
+ * Calculates the distance from the specified edge (left or right) where the column
832
+ * should be positioned. Returns `null` if the column is not sticky in the given direction.
833
+ *
834
+ * @param key - The unique identifier for the column
835
+ * @param dir - The direction to check ('left' or 'right')
836
+ * @returns Offset in pixels, or `null` if not sticky in the specified direction
837
+ */
323
838
  stickyOffset = (key, dir) => dir === 'left' && this.isStickyLeft(key)
324
839
  ? (this.#stickyLeftMap.get(key) ?? null)
325
840
  : dir === 'right' && this.isStickyRight(key)
326
841
  ? (this.#stickyRightMap.get(key) ?? null)
327
842
  : null;
843
+ /**
844
+ * Calculates and updates scrollbar state based on the current scroll position.
845
+ *
846
+ * Computes whether the scrollbar should be visible, and if so, determines
847
+ * the thumb height and position based on scroll height, client height, and scroll position.
848
+ * Updates the corresponding signal properties with the calculated values.
849
+ */
328
850
  calcScrollbar() {
329
851
  const el = this.scrollEl()?.nativeElement;
330
852
  if (!el)
@@ -354,18 +876,77 @@ class DataGridVm {
354
876
  acc += this.widthByKey(col.key);
355
877
  }
356
878
  }
357
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridVm, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
358
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridVm });
879
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
880
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm });
359
881
  }
360
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridVm, decorators: [{
882
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridVm, decorators: [{
361
883
  type: Injectable
362
884
  }], ctorParameters: () => [] });
363
885
 
886
+ /**
887
+ * Component for rendering individual data grid cells.
888
+ *
889
+ * Handles different cell rendering strategies based on column configuration:
890
+ * - Custom templates via `renderTemplate`
891
+ * - Global type-specific templates registered in DataGridVm
892
+ * - Built-in formatters for dates and numbers
893
+ * - Index display (1-based row numbering)
894
+ * - Plain text for simple values
895
+ *
896
+ * The component automatically determines the appropriate rendering method
897
+ * based on column properties and applies Angular pipes when needed.
898
+ *
899
+ * @template Data - Type of data objects in the grid row
900
+ *
901
+ * @example
902
+ * ```html
903
+ * <re-data-grid-cell
904
+ * [index]="0"
905
+ * [item]="rowData"
906
+ * [column]="columnConfig"
907
+ * />
908
+ * ```
909
+ */
364
910
  class DataGridCellComponent {
911
+ /**
912
+ * Zero-based index of the current row in the data grid.
913
+ *
914
+ * Used for rendering row numbers (displayed as 1-based in 'index' type columns)
915
+ * and passed to custom templates as context.
916
+ */
365
917
  index = input.required(...(ngDevMode ? [{ debugName: "index" }] : []));
918
+ /**
919
+ * Data object for the current row.
920
+ *
921
+ * Contains the complete row data that can be accessed by column value functions
922
+ * or custom render templates. Type-safe according to the Data generic parameter.
923
+ */
366
924
  item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
925
+ /**
926
+ * Column configuration object.
927
+ *
928
+ * Defines how the cell should be rendered, including key mapping, type,
929
+ * custom templates, or value transformation functions.
930
+ */
367
931
  column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
932
+ /**
933
+ * Injected DataGridVm service instance.
934
+ *
935
+ * Provides access to global type-specific cell templates registered
936
+ * at the grid level via `globalTypeCellTpls` map.
937
+ */
368
938
  vm = inject(DataGridVm);
939
+ /**
940
+ * Computed rendering strategy for the current cell.
941
+ *
942
+ * Determines which template block to use based on column configuration:
943
+ * - `'tpl'` - Custom column template (`renderTemplate` property exists)
944
+ * - `'globalTypeTpl'` - Global type template (registered in DataGridVm)
945
+ * - `'date'`, `'number'`, `'index'` - Built-in formatters
946
+ * - `'plain'` - Default text rendering
947
+ *
948
+ * The value is reactive and updates when column configuration changes.
949
+ */
369
950
  type = computed(() => {
370
951
  const col = this.column();
371
952
  if ('renderTemplate' in col) {
@@ -374,15 +955,28 @@ class DataGridCellComponent {
374
955
  if ('type' in col && this.vm.globalTypeCellTpls.has(col.type)) {
375
956
  return 'globalTypeTpl';
376
957
  }
958
+ if (this.vm.globalDataCellTpls.has(col.key)) {
959
+ return 'globalDataTpl';
960
+ }
377
961
  return 'type' in col ? col['type'] : 'plain';
378
962
  }, ...(ngDevMode ? [{ debugName: "type" }] : []));
963
+ /**
964
+ * Computed cell value extracted from row data.
965
+ *
966
+ * Returns the cell's display value by either:
967
+ * - Calling the `value` function from column configuration (if defined)
968
+ * - Directly accessing the row property using the column's `key`
969
+ *
970
+ * The value is reactive and updates when row data or column configuration changes.
971
+ * Used as input for templates, pipes, and default text rendering.
972
+ */
379
973
  value = computed(() => {
380
974
  const col = this.column();
381
975
  const row = this.item();
382
976
  return 'value' in col ? col.value(row) : row[col.key];
383
977
  }, ...(ngDevMode ? [{ debugName: "value" }] : []));
384
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
385
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", 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: `
978
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
979
+ 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: `
386
980
  @let row = item();
387
981
  @let col = column();
388
982
  @let val = value();
@@ -400,11 +994,17 @@ class DataGridCellComponent {
400
994
  [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
401
995
  />
402
996
  }
997
+ @case ('globalDataTpl') {
998
+ <ng-container
999
+ [ngTemplateOutlet]="vm.globalDataCellTpls.get($any(col).key)"
1000
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1001
+ />
1002
+ }
403
1003
  @case ('date') {
404
- {{ val | date }}
1004
+ {{ val | date: $any(col)?.typeParams }}
405
1005
  }
406
1006
  @case ('number') {
407
- {{ val | number }}
1007
+ {{ val | number: $any(col)?.typeParams }}
408
1008
  }
409
1009
  @case ('index') {
410
1010
  {{ index() + 1 }}
@@ -415,7 +1015,7 @@ class DataGridCellComponent {
415
1015
  }
416
1016
  `, isInline: true, styles: [":host{width:100%;text-align:inherit}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: DecimalPipe, name: "number" }] });
417
1017
  }
418
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellComponent, decorators: [{
1018
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridCellComponent, decorators: [{
419
1019
  type: Component,
420
1020
  args: [{ selector: 're-data-grid-cell', template: `
421
1021
  @let row = item();
@@ -435,11 +1035,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
435
1035
  [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
436
1036
  />
437
1037
  }
1038
+ @case ('globalDataTpl') {
1039
+ <ng-container
1040
+ [ngTemplateOutlet]="vm.globalDataCellTpls.get($any(col).key)"
1041
+ [ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
1042
+ />
1043
+ }
438
1044
  @case ('date') {
439
- {{ val | date }}
1045
+ {{ val | date: $any(col)?.typeParams }}
440
1046
  }
441
1047
  @case ('number') {
442
- {{ val | number }}
1048
+ {{ val | number: $any(col)?.typeParams }}
443
1049
  }
444
1050
  @case ('index') {
445
1051
  {{ index() + 1 }}
@@ -451,19 +1057,87 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
451
1057
  `, imports: [NgTemplateOutlet, DatePipe, DecimalPipe], styles: [":host{width:100%;text-align:inherit}\n"] }]
452
1058
  }], 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 }] }] } });
453
1059
 
1060
+ /**
1061
+ * Service class for managing row selection in a data grid.
1062
+ *
1063
+ * Handles selection state and operations for grid rows, supporting multiple selection modes
1064
+ * (none, single, multi). Provides reactive signals for tracking selected items and
1065
+ * computed values for selection state.
1066
+ *
1067
+ * @template Data - The type of data objects in the grid, must extend `AnyDict`.
1068
+ *
1069
+ * @example
1070
+ * ```typescript
1071
+ * const selector = new Selector<User>();
1072
+ * selector.data.set(users);
1073
+ * selector.selection.set({ mode: 'multi', key: 'id' });
1074
+ * selector.select(users[0]);
1075
+ * console.log(selector.selectedKeys()); // ['user-id']
1076
+ * ```
1077
+ */
454
1078
  class Selector {
1079
+ /**
1080
+ * Signal containing the full dataset of grid rows.
1081
+ *
1082
+ * This signal holds all data items that can be selected.
1083
+ * Defaults to an empty array.
1084
+ */
455
1085
  data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1086
+ /**
1087
+ * Signal containing the current selection configuration.
1088
+ *
1089
+ * Defines the selection mode and the key property used for identifying rows.
1090
+ * Defaults to `{ mode: 'none' }` which disables selection.
1091
+ */
456
1092
  selection = signal({ mode: 'none' }, ...(ngDevMode ? [{ debugName: "selection" }] : []));
1093
+ /**
1094
+ * Signal containing the array of currently selected row keys.
1095
+ *
1096
+ * Stores the keys of all selected rows based on the key property
1097
+ * defined in the selection configuration.
1098
+ * Defaults to an empty array.
1099
+ */
457
1100
  selectedKeys = signal([], ...(ngDevMode ? [{ debugName: "selectedKeys" }] : []));
1101
+ /**
1102
+ * Computed signal indicating the overall selection state of all rows.
1103
+ *
1104
+ * Returns:
1105
+ * - `true` if all rows are selected
1106
+ * - `false` if no rows are selected
1107
+ * - `'mixed'` if some but not all rows are selected
1108
+ *
1109
+ * Useful for implementing "select all" checkbox with indeterminate state.
1110
+ */
458
1111
  isAllSelected = computed(() => {
459
1112
  const selectedCount = this.selectedKeys().length;
460
1113
  return selectedCount === this.data().length ? true : selectedCount === 0 ? false : 'mixed';
461
1114
  }, ...(ngDevMode ? [{ debugName: "isAllSelected" }] : []));
1115
+ /**
1116
+ * Checks whether a specific row is currently selected.
1117
+ *
1118
+ * Compares the row's key value against the list of selected keys.
1119
+ * Returns `false` if selection mode is 'none' or key is not configured.
1120
+ *
1121
+ * @param row - The data row to check selection status for.
1122
+ * @returns `true` if the row is selected, `false` otherwise.
1123
+ */
462
1124
  isSelected(row) {
463
1125
  const selection = this.selection();
464
1126
  const selected = this.selectedKeys();
465
1127
  return 'key' in selection ? selected.includes(row[selection.key]) : false;
466
1128
  }
1129
+ /**
1130
+ * Toggles selection of all rows.
1131
+ *
1132
+ * If all rows are selected, deselects all.
1133
+ * If no rows or some rows are selected, selects all.
1134
+ *
1135
+ * This method only works in `'multi'` selection mode and throws an error
1136
+ * if called in any other mode.
1137
+ *
1138
+ * @returns The updated array of selected keys.
1139
+ * @throws {Error} If selection mode is not `'multi'`.
1140
+ */
467
1141
  selectAll() {
468
1142
  if (this.selection().mode !== 'multi') {
469
1143
  throw new Error('Cannot select all in not "multi" mode');
@@ -474,6 +1148,18 @@ class Selector {
474
1148
  this.selectedKeys.set(!nextState ? [] : this.data().map((row) => row[selection.key]));
475
1149
  return this.selectedKeys();
476
1150
  }
1151
+ /**
1152
+ * Selects or deselects a specific row.
1153
+ *
1154
+ * Behavior depends on the selection mode:
1155
+ * - In `'single'` mode: replaces current selection with the specified row.
1156
+ * - In `'multi'` mode: toggles the row's selection state (adds if not selected, removes if selected).
1157
+ * - In `'none'` mode: throws an error.
1158
+ *
1159
+ * @param row - The data row to select or deselect.
1160
+ * @returns The updated array of selected keys after the operation.
1161
+ * @throws {Error} If selection mode is `'none'`.
1162
+ */
477
1163
  select(row) {
478
1164
  if (this.selection().mode === 'none') {
479
1165
  throw new Error('Cannot select row in "none" mode');
@@ -525,8 +1211,8 @@ class CheckboxIcon {
525
1211
  }
526
1212
  });
527
1213
  }
528
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: CheckboxIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
529
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: CheckboxIcon, isStandalone: true, selector: "re-checkbox-ic", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "boxRef", first: true, predicate: (ElementRef), descendants: true, isSignal: true }], ngImport: i0, template: `
1214
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CheckboxIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
1215
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.1", type: CheckboxIcon, isStandalone: true, selector: "re-checkbox-ic", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "boxRef", first: true, predicate: (ElementRef), descendants: true, isSignal: true }], ngImport: i0, template: `
530
1216
  <label class="cb" [class.cb--disabled]="disabled()">
531
1217
  <input
532
1218
  #box
@@ -542,7 +1228,7 @@ class CheckboxIcon {
542
1228
  </label>
543
1229
  `, isInline: true, styles: [":host{--re-data-grid-checkbox-size: 20px;--re-data-grid-checkbox-stroke: 2px;--re-data-grid-checkbox-border: var(--border-color, #9aa3af);--re-data-grid-checkbox-tick: var(--surface-neutral, #fff);--re-data-grid-checkbox-surface: var(--surface-neutral, #fff);--re-data-grid-checkbox-active-color: var(--primary-color, #2563eb);display:inline-block;width:var(--re-data-grid-checkbox-size);height:var(--re-data-grid-checkbox-size);-webkit-user-select:none;user-select:none}.cb{cursor:default;display:inline-block}.cb--disabled{opacity:.6}.cb__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.cb__box{position:relative;display:inline-block;width:var(--re-data-grid-checkbox-size);height:var(--re-data-grid-checkbox-size);border:var(--re-data-grid-checkbox-stroke) solid var(--re-data-grid-checkbox-border);border-radius:4px;background:var(--re-data-grid-checkbox-surface);transition:background .25s,border-color .25s}.cb__input:checked+.cb__box{border-color:var(--re-data-grid-checkbox-active-color);background:var(--re-data-grid-checkbox-active-color)}.cb__input:checked+.cb__box:after{content:\"\";position:absolute;inset:0;margin:auto;width:10px;height:6px;border:2px solid var(--re-data-grid-checkbox-tick);border-top:0;border-right:0;transform:rotate(-45deg) translate(1px,-1px) scale(.8);opacity:0;animation:tick .25s forwards ease}.cb__input[data-indeterminate=true]+.cb__box{background:var(--re-data-grid-checkbox-active-color);border-color:var(--re-data-grid-checkbox-active-color)}.cb__input[data-indeterminate=true]+.cb__box:after{content:\"\";position:absolute;left:3px;right:3px;top:50%;border-top:2px solid var(--re-data-grid-checkbox-tick);transform:translateY(-50%) scaleX(.3);opacity:0;animation:dash .25s forwards ease}@keyframes tick{to{opacity:1;transform:rotate(-45deg) translate(1px,-1px) scale(1)}}@keyframes dash{to{opacity:1;transform:translateY(-50%) scaleX(1)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
544
1230
  }
545
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: CheckboxIcon, decorators: [{
1231
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CheckboxIcon, decorators: [{
546
1232
  type: Component,
547
1233
  args: [{ selector: 're-checkbox-ic', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
548
1234
  <label class="cb" [class.cb--disabled]="disabled()">
@@ -564,8 +1250,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
564
1250
  /* eslint-disable max-len */
565
1251
  class ExpandIcon {
566
1252
  expanded = input(false, { ...(ngDevMode ? { debugName: "expanded" } : {}), transform: booleanAttribute });
567
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ExpandIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
568
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ExpandIcon, isStandalone: true, selector: "re-expand-ic", inputs: { expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1253
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ExpandIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
1254
+ 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: `
569
1255
  @if (expanded()) {
570
1256
  <svg width="16" height="16" viewBox="0 0 16 16">
571
1257
  <path
@@ -583,7 +1269,7 @@ class ExpandIcon {
583
1269
  }
584
1270
  `, isInline: true, styles: [""] });
585
1271
  }
586
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ExpandIcon, decorators: [{
1272
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ExpandIcon, decorators: [{
587
1273
  type: Component,
588
1274
  args: [{ selector: 're-expand-ic', template: `
589
1275
  @if (expanded()) {
@@ -607,8 +1293,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
607
1293
  /* eslint-disable max-len */
608
1294
  class SortIcon {
609
1295
  direction = input('asc', ...(ngDevMode ? [{ debugName: "direction" }] : []));
610
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: SortIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
611
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.3", type: SortIcon, isStandalone: true, selector: "re-sort-ic", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1296
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SortIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
1297
+ 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: `
612
1298
  <svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
613
1299
  <path
614
1300
  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"
@@ -617,7 +1303,7 @@ class SortIcon {
617
1303
  </svg>
618
1304
  `, 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"] });
619
1305
  }
620
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: SortIcon, decorators: [{
1306
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SortIcon, decorators: [{
621
1307
  type: Component,
622
1308
  args: [{ selector: 're-sort-ic', template: `
623
1309
  <svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
@@ -629,57 +1315,192 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
629
1315
  `, styles: ["svg{transition:transform .3s ease-in-out}svg:not(.asc):not(.desc){display:none}.asc{transform:rotate(-180deg)}.desc{transform:rotate(0)}\n"] }]
630
1316
  }], propDecorators: { direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }] } });
631
1317
 
1318
+ /**
1319
+ * Data grid component with virtual scrolling, sorting, selection, and pagination support.
1320
+ *
1321
+ * Provides high-performance rendering of large datasets with features like:
1322
+ * - Virtual scrolling for efficient DOM management
1323
+ * - Column sorting and expandable columns
1324
+ * - Row selection (single/multiple)
1325
+ * - Pagination modes: none, pagination, or infinite scroll
1326
+ * - Pinned rows
1327
+ * - Custom cell and header templates
1328
+ *
1329
+ * @example
1330
+ * ```html
1331
+ * <re-data-grid
1332
+ * [data]="users"
1333
+ * [columns]="columns"
1334
+ * [selection]="{ mode: 'multiple' }"
1335
+ * (sortChange)="onSort($event)"
1336
+ * />
1337
+ * ```
1338
+ */
632
1339
  class DataGrid {
633
- /** Массив данных для отображения в таблице */
1340
+ /**
1341
+ * Array of data to display in the table.
1342
+ *
1343
+ * Each item represents a single row. The component will efficiently render
1344
+ * only visible rows using virtual scrolling.
1345
+ */
634
1346
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
635
- /** Конфигурация колонок таблицы */
1347
+ /**
1348
+ * Column configuration for the table.
1349
+ *
1350
+ * Defines how each column should be rendered, sorted, and styled.
1351
+ * Supports custom templates, sorting keys, and expandable columns.
1352
+ */
636
1353
  columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
637
- /** Режим пагинации: 'none', 'pagination' или 'infinity' */
1354
+ /**
1355
+ * Pagination mode: 'none', 'pagination', or 'infinity'.
1356
+ *
1357
+ * - `none` - No pagination, all data is rendered
1358
+ * - `pagination` - Classic page-based pagination with fixed page size
1359
+ * - `infinity` - Infinite scroll mode, loads more data as user scrolls
1360
+ */
638
1361
  mode = input('none', ...(ngDevMode ? [{ debugName: "mode" }] : []));
639
- /** Массив закрепленных строк */
1362
+ /**
1363
+ * Array of pinned rows that remain visible at the top or bottom.
1364
+ *
1365
+ * Pinned rows stay fixed while the rest of the content scrolls.
1366
+ * Useful for totals, summaries, or always-visible items.
1367
+ */
640
1368
  pinnedRows = input([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
641
- /** Добавить ли номерную колонку */
1369
+ /**
1370
+ * Whether to add an index column showing row numbers.
1371
+ *
1372
+ * When enabled, it automatically adds a column displaying sequential row numbers.
1373
+ */
642
1374
  hasIndexColumn = input(false, { ...(ngDevMode ? { debugName: "hasIndexColumn" } : {}), transform: booleanAttribute });
643
- /** Поддержка выбора строк */
1375
+ /**
1376
+ * Row selection configuration.
1377
+ *
1378
+ * Controls whether users can select rows and in what mode:
1379
+ * - `{ mode: 'none' }` - No selection
1380
+ * - `{ mode: 'single' }` - Single row selection
1381
+ * - `{ mode: 'multi' }` - Multiple row selection with checkboxes
1382
+ *
1383
+ * When selection is enabled, a `key` must be provided to identify rows.
1384
+ */
644
1385
  selection = input({ mode: 'none' }, ...(ngDevMode ? [{ debugName: "selection" }] : []));
645
- /** Количество элементов на странице */
1386
+ /**
1387
+ * Number of items per page.
1388
+ *
1389
+ * Used in pagination and infinity scroll modes to control
1390
+ * how many rows are loaded at once. Default is 20.
1391
+ */
646
1392
  pageSize = input(20, { ...(ngDevMode ? { debugName: "pageSize" } : {}), transform: numberAttribute });
647
- /** Высота строки в пикселях */
1393
+ /**
1394
+ * Height of each row in pixels.
1395
+ *
1396
+ * Used for virtual scrolling calculations. Must be consistent
1397
+ * across all rows for accurate scrolling. Default is 40.
1398
+ */
648
1399
  rowHeight = input(40, { ...(ngDevMode ? { debugName: "rowHeight" } : {}), transform: numberAttribute });
649
- /** Заполнять ли доступную высоту */
650
- fillHeight = input(true, { ...(ngDevMode ? { debugName: "fillHeight" } : {}), transform: booleanAttribute });
651
- /** Размер буфера виртуального скролла */
1400
+ /**
1401
+ * Grid height configuration.
1402
+ *
1403
+ * - `number` - Fixed height in pixels
1404
+ * - `'full'` - Fill container height (100%), can be managed by host component style
1405
+ * - `'default'` - Height by CSS var (--re-data-grid-height)
1406
+ */
1407
+ height = input('default', ...(ngDevMode ? [{ debugName: "height" }] : []));
1408
+ /**
1409
+ * Size of the virtual scroll buffer.
1410
+ *
1411
+ * Number of extra rows to render above and below the viewport
1412
+ * to reduce flickering during fast scrolling. Default is 6.
1413
+ */
652
1414
  virtualBuffer = input(6, ...(ngDevMode ? [{ debugName: "virtualBuffer" }] : []));
653
- /** Состояние загрузки данных */
1415
+ /**
1416
+ * Loading state indicator.
1417
+ *
1418
+ * When true, displays loading template instead of data.
1419
+ * Useful during async data fetching operations.
1420
+ */
654
1421
  loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : {}), transform: booleanAttribute });
655
- /** Функция или имя свойства для получения уникального ключа строки */
1422
+ /**
1423
+ * Function or property name for obtaining a unique row key.
1424
+ *
1425
+ * Used for efficient change detection and row tracking.
1426
+ * Can be a property name (string) or a function that returns a unique identifier.
1427
+ */
656
1428
  rowKey = input(undefined, ...(ngDevMode ? [{ debugName: "rowKey" }] : []));
657
- /** Начинать отсчёт пагинации с 1 (false) или 0 (true) */
1429
+ /**
1430
+ * Whether to start a page count from 0 (true) or 1 (false).
1431
+ *
1432
+ * Controls the numbering scheme for pagination events.
1433
+ * Default is true (0-based indexing).
1434
+ */
658
1435
  pageStartFromZero = input(true, { ...(ngDevMode ? { debugName: "pageStartFromZero" } : {}), transform: booleanAttribute });
659
- /** Событие запроса данных */
1436
+ /**
1437
+ * Event emitted when requesting data for a new page.
1438
+ *
1439
+ * Fired in pagination and infinity scroll modes when the user navigates
1440
+ * to a different page or scrolls near the end of current data.
1441
+ *
1442
+ * @example
1443
+ * ```typescript
1444
+ * onPageChange(event: GridPageChangeEvent) {
1445
+ * this.loadData(event.page, event.rows);
1446
+ * }
1447
+ * ```
1448
+ */
660
1449
  pageChange = output();
661
- /** Событие изменения сортировки */
1450
+ /**
1451
+ * Event emitted when sort order changes.
1452
+ *
1453
+ * Fired when a user clicks on a sortable column header.
1454
+ * Contains the sort key and direction (asc/desc).
1455
+ *
1456
+ * @example
1457
+ * ```typescript
1458
+ * onSortChange(event: GridSortEvent<User>) {
1459
+ * this.data = sortBy(this.data, event.key, event.order);
1460
+ * }
1461
+ * ```
1462
+ */
662
1463
  sortChange = output();
663
- /** Событие изменения выбранных строк */
1464
+ /**
1465
+ * Event emitted when selected rows change.
1466
+ *
1467
+ * Fired when a user selects or deselects rows.
1468
+ * Contains an array of currently selected row keys.
1469
+ */
664
1470
  selectChange = output();
665
- /** Событие клика по строке */
1471
+ /**
1472
+ * Event emitted when a row is clicked.
1473
+ *
1474
+ * Contains the clicked row data and its index.
1475
+ */
666
1476
  rowClick = output();
667
- /** Событие клика по ячейке */
1477
+ /**
1478
+ * Event emitted when a cell is clicked.
1479
+ *
1480
+ * Contains the clicked row, column configuration, and row index.
1481
+ */
668
1482
  cellClick = output();
669
1483
  vm = inject((DataGridVm));
670
1484
  selector = new Selector();
671
1485
  rootEl = viewChild('root', ...(ngDevMode ? [{ debugName: "rootEl" }] : []));
672
1486
  scrollEl = viewChild('scroll', ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
673
1487
  headerEl = viewChild('header', ...(ngDevMode ? [{ debugName: "headerEl" }] : []));
674
- cellSlotRefs = contentChildren(DataGridTypeCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellSlotRefs" }] : []));
1488
+ cellTypedSlotRefs = contentChildren(DataGridTypeCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellTypedSlotRefs" }] : []));
1489
+ cellDataSlotRefs = contentChildren(DataGridCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellDataSlotRefs" }] : []));
675
1490
  headerSlotRefs = contentChildren(DataGridHeaderTemplateDirective, ...(ngDevMode ? [{ debugName: "headerSlotRefs" }] : []));
676
1491
  emptySlotRefs = contentChildren(DataGridCellEmptyDirective, ...(ngDevMode ? [{ debugName: "emptySlotRefs" }] : []));
677
1492
  loadingSlotRefs = contentChildren(DataGridCellLoadingDirective, ...(ngDevMode ? [{ debugName: "loadingSlotRefs" }] : []));
1493
+ sortIcSlotRefs = contentChildren(DataGridSortIconDirective, ...(ngDevMode ? [{ debugName: "sortIcSlotRefs" }] : []));
1494
+ expanderIcSlotRefs = contentChildren(DataGridExpanderIconDirective, ...(ngDevMode ? [{ debugName: "expanderIcSlotRefs" }] : []));
678
1495
  emptyTpl = computed(() => this.emptySlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "emptyTpl" }] : []));
679
1496
  loadingTpl = computed(() => this.loadingSlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "loadingTpl" }] : []));
1497
+ sortTpl = computed(() => this.sortIcSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "sortTpl" }] : []));
1498
+ expanderTpl = computed(() => this.expanderIcSlotRefs()?.at(0), ...(ngDevMode ? [{ debugName: "expanderTpl" }] : []));
680
1499
  visibleRows = signal([], ...(ngDevMode ? [{ debugName: "visibleRows" }] : []));
681
1500
  startIndex = 0;
682
1501
  headerHeight = signal(40, ...(ngDevMode ? [{ debugName: "headerHeight" }] : []));
1502
+ // todo someday
1503
+ // protected fillHeight = signal<number | null>(null);
683
1504
  expanderMap = signal(new Map(), ...(ngDevMode ? [{ debugName: "expanderMap" }] : []));
684
1505
  extendedColumns = computed(() => {
685
1506
  const hasSelection = this.selection().mode !== 'none';
@@ -689,6 +1510,24 @@ class DataGrid {
689
1510
  hasIndex && newColumns.push(GRID_INDEX_COLUMN);
690
1511
  return [...newColumns, ...this.columns()];
691
1512
  }, ...(ngDevMode ? [{ debugName: "extendedColumns" }] : []));
1513
+ /**
1514
+ * Computed CSS height value based on height setting.
1515
+ */
1516
+ styleHeight = computed(() => {
1517
+ const height = this.height();
1518
+ if (typeof height === 'number') {
1519
+ return `${height}px`;
1520
+ // todo someday
1521
+ // } else if (height === 'fill') {
1522
+ // const h = this.fillHeight();
1523
+ //
1524
+ // return h === null ? null : `${h}px`;
1525
+ }
1526
+ else if (height === 'full') {
1527
+ return '100%';
1528
+ }
1529
+ return 'var(--re-data-grid-height)';
1530
+ }, ...(ngDevMode ? [{ debugName: "styleHeight" }] : []));
692
1531
  hideSbTimeout;
693
1532
  currentSortField;
694
1533
  currentSortOrder = 'asc';
@@ -726,12 +1565,18 @@ class DataGrid {
726
1565
  clearTimeout(this.hideSbTimeout);
727
1566
  });
728
1567
  }
729
- get styleHeight() {
730
- return this.fillHeight() ? null : 'auto';
731
- }
732
1568
  resolvePinnedData(pr) {
733
1569
  return typeof pr.data === 'function' ? pr.data() : pr.data;
734
1570
  }
1571
+ /**
1572
+ * Handles column header click for sorting.
1573
+ *
1574
+ * Toggles sort order between ascending and descending for the clicked column.
1575
+ * If a different column is clicked, it resets to ascending order.
1576
+ * Emits sortChange event with the current sort state.
1577
+ *
1578
+ * @param col - Column configuration that was clicked
1579
+ */
735
1580
  onSort(col) {
736
1581
  if (!col.sortKey) {
737
1582
  return;
@@ -745,6 +1590,16 @@ class DataGrid {
745
1590
  }
746
1591
  this.sortChange.emit({ key: this.currentSortField, order: this.currentSortOrder });
747
1592
  }
1593
+ /**
1594
+ * Handles cell click events.
1595
+ *
1596
+ * Emits cellClick event and handles row selection if selection mode is enabled.
1597
+ * Updates the selection state and emits selectChange event accordingly.
1598
+ *
1599
+ * @param row - Data row that was clicked
1600
+ * @param col - Column configuration of the clicked cell
1601
+ * @param index - Row index in the dataset
1602
+ */
748
1603
  onCellClick(row, col, index) {
749
1604
  this.cellClick.emit({ row, col, index });
750
1605
  if (this.selection().mode !== 'none') {
@@ -756,6 +1611,14 @@ class DataGrid {
756
1611
  const keys = this.expanderMap();
757
1612
  return keys.has(column.key);
758
1613
  }
1614
+ /**
1615
+ * Handles column expand/collapse toggle.
1616
+ *
1617
+ * Toggles the expanded state of a column and updates the visibility
1618
+ * of all dependent columns that reference this column via expandBy property.
1619
+ *
1620
+ * @param column - Column configuration to expand or collapse
1621
+ */
759
1622
  onExpand(column) {
760
1623
  const expanded = !this.expanderMap().get(column.key);
761
1624
  this.expanderMap.update((prev) => {
@@ -766,6 +1629,15 @@ class DataGrid {
766
1629
  const columns = this.extendedColumns().map((col) => col.expandBy === column.key ? { ...col, visible: expanded } : col);
767
1630
  this.vm.columns.set(columns);
768
1631
  }
1632
+ /**
1633
+ * Handles vertical scroll events and updates visible rows.
1634
+ *
1635
+ * Implements virtual scrolling by calculating which rows should be rendered
1636
+ * based on the current scroll position. Also handles infinite scroll data loading
1637
+ * when the user scrolls near the end of available data.
1638
+ *
1639
+ * @param initial - Whether this is the initial scroll calculation
1640
+ */
769
1641
  onVerticalScroll(initial = false) {
770
1642
  const el = this.scrollEl()?.nativeElement;
771
1643
  if (!el)
@@ -805,6 +1677,15 @@ class DataGrid {
805
1677
  this.hideScrollbarSoon();
806
1678
  }
807
1679
  onHorizontalScroll() { }
1680
+ /**
1681
+ * Handles mouse down event on scrollbar thumb for drag scrolling.
1682
+ *
1683
+ * Initiates dragging mode and sets up mouse move/up event listeners
1684
+ * to track thumb position and update scroll position accordingly.
1685
+ * Automatically cleans up listeners when dragging ends.
1686
+ *
1687
+ * @param e - Mouse down event from a scrollbar thumb element
1688
+ */
808
1689
  onThumbDown(e) {
809
1690
  e.preventDefault();
810
1691
  e.stopPropagation();
@@ -877,9 +1758,12 @@ class DataGrid {
877
1758
  this.selector.selection.set(this.selection());
878
1759
  }
879
1760
  initRefs() {
880
- this.cellSlotRefs()?.forEach((dir) => this.vm.globalTypeCellTpls.set(dir.type(), dir.tpl));
1761
+ this.cellTypedSlotRefs()?.forEach((dir) => this.vm.globalTypeCellTpls.set(dir.type(), dir.tpl));
1762
+ this.cellDataSlotRefs()?.forEach((dir) => this.vm.globalDataCellTpls.set(dir.key(), dir.tpl));
881
1763
  const headerMap = new Map();
1764
+ const cellsMap = new Map();
882
1765
  this.headerSlotRefs()?.forEach((h) => headerMap.set(h.key(), h.tpl));
1766
+ this.cellDataSlotRefs()?.forEach((h) => cellsMap.set(h.key(), h.tpl));
883
1767
  this.extendedColumns()?.forEach((c) => {
884
1768
  if (!c.headerTemplate && headerMap.has(c.key)) {
885
1769
  c.headerTemplate = headerMap.get(c.key);
@@ -934,17 +1818,17 @@ class DataGrid {
934
1818
  this.vm.columns.set(columns);
935
1819
  this.expanderMap.set(map);
936
1820
  }
937
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
938
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", 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 }, 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 }, fillHeight: { classPropertyName: "fillHeight", publicName: "fillHeight", isSignal: true, isRequired: false, transformFunction: null }, virtualBuffer: { classPropertyName: "virtualBuffer", publicName: "virtualBuffer", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, pageStartFromZero: { classPropertyName: "pageStartFromZero", publicName: "pageStartFromZero", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", sortChange: "sortChange", selectChange: "selectChange", rowClick: "rowClick", cellClick: "cellClick" }, providers: [DataGridVm], queries: [{ propertyName: "cellSlotRefs", predicate: DataGridTypeCellTemplateDirective, isSignal: true }, { propertyName: "headerSlotRefs", predicate: DataGridHeaderTemplateDirective, isSignal: true }, { propertyName: "emptySlotRefs", predicate: DataGridCellEmptyDirective, isSignal: true }, { propertyName: "loadingSlotRefs", predicate: DataGridCellLoadingDirective, 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 }], ngImport: i0, template: "@let items = data();\n@let empty = !loading() && !items?.length;\n@let notEmpty = !!items?.length;\n\n@let pinnedTopH = vm.pinnedTop().length * rowHeight();\n@let pinnedBottomH = vm.pinnedBottom().length * rowHeight();\n\n<div\n #root\n class=\"re-dg-root\"\n [class.fill]=\"fillHeight()\"\n [class.loading]=\"loading()\"\n [style.height]=\"styleHeight\"\n role=\"table\"\n>\n @if (loading()) {\n <div class=\"re-dg-loader\">\n @let loadingTemplate = loadingTpl();\n\n @if (loadingTemplate?.tpl) {\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\n } @else {\n <span class=\"re-dg-loader-text\">\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026</span>\n }\n </div>\n }\n\n <div\n #scroll\n class=\"re-dg-body\"\n role=\"rowgroup\"\n (mouseenter)=\"showScrollbar()\"\n (mouseleave)=\"hideScrollbarSoon()\"\n >\n <div class=\"re-dg-header\" role=\"rowgroup\">\n <div #header class=\"re-dg-row re-dg-header-row\" role=\"row\">\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-header-cell\"\n role=\"columnheader\"\n [class.sortable]=\"!!col.sortKey\"\n [class.active-sort]=\"currentSortField && (currentSortField === col.sortKey)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [style.min-width.px]=\"col.minWidth || null\"\n [style.max-width.px]=\"col.maxWidth || null\"\n [style.justify-content]=\"col.align || 'left'\"\n [attr.aria-sort]=\"ariaSort(col)\"\n [attr.tabindex]=\"col.sortKey ? 0 : -1\"\n [title]=\"col.header\"\n (click)=\"col.sortKey && onSort(col)\"\n (keydown.enter)=\"col.sortKey && onSort(col)\"\n >\n {{currentSortField }} {{ col.sortKey}}\n @if (col.headerTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"col.headerTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: col.header }\"\n />\n } @else {\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n @let isMultiSelect = selection().mode === 'multi';\n\n @if (isCheckbox && isMultiSelect) {\n <re-checkbox-ic mixable [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\n } @else {\n <span class=\"re-dg-header-text\">{{ col.header }}</span>\n }\n\n @if (col.sortKey) {\n <span class=\"re-dg-sort-ind\">\n <re-sort-ic [direction]=\"currentSortField === col.sortKey ? currentSortOrder : 'desc'\" />\n </span>\n }\n\n @if (isExpandable(col)) {\n <button (click)=\"$event.stopPropagation(); onExpand(col)\">\n <re-expand-ic [expanded]=\"expanderMap().get(col.key)\" />\n </button>\n }\n }\n </div>\n }\n </div>\n\n <!-- PINNED TOP ROWS -->\n @if (notEmpty) {\n @for (pr of vm.pinnedTop(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-top\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n }\n </div>\n\n @if (empty) {\n @let emptyTemplate = emptyTpl()?.tpl;\n\n <div class=\"re-dg-empty\">\n @if (emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"emptyTemplate\" />\n } @else {\n <span class=\"re-dg-empty-text\">\u041D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445</span>\n }\n </div>\n }\n\n <!-- Content -->\n @if (notEmpty) {\n <div class=\"re-dg-spacer\" [style.height.px]=\"items.length * rowHeight() - pinnedBottomH\"></div>\n\n @for (row of visibleRows(); track trackByRow(row); let vi = $index) {\n <div\n class=\"re-dg-row re-dg-data-row\"\n role=\"row\"\n [style.height.px]=\"rowHeight()\"\n [style.top.px]=\"(startIndex + vi) * rowHeight() + pinnedTopH + headerHeight()\"\n [attr.tabindex]=\"0\"\n (click)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n >\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class]=\"cellClass(col, row)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.text-align]=\"col.align || 'left'\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [attr.tabindex]=\"0\"\n (click)=\"onCellClick(row, col, startIndex + vi);\"\n (keydown.enter)=\"onCellClick(row, col, startIndex + vi)\"\n >\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n\n @if (isCheckbox) {\n <re-checkbox-ic mixable=\"false\" [state]=\"selector.isSelected(row)\" />\n } @else {\n <re-data-grid-cell [index]=\"startIndex + vi\" [item]=\"row\" [column]=\"col\" />\n }\n </div>\n }\n </div>\n }\n }\n\n <!-- PINNED BOTTOM ROWS -->\n @if (notEmpty) {\n <div class=\"re-dg-footer\" role=\"rowgroup\">\n @for (pr of vm.pinnedBottom(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-bottom\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Overlay scrollbar -->\n <div class=\"re-dg-scrollbar\" [class.visible]=\"vm.scrollbarVisible()\">\n <div\n class=\"re-dg-scrollbar-thumb\"\n role=\"scrollbar\"\n aria-orientation=\"vertical\"\n aria-hidden=\"false\"\n [style.height.px]=\"vm.thumbHeightPx()\"\n [style.transform]=\"'translateY(' + vm.thumbTopPx() + 'px)'\"\n (mousedown)=\"onThumbDown($event)\"\n ></div>\n </div>\n</div>\n", styles: [":host{--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: #fff;--re-data-grid-active: #2a90f4;--re-data-grid-empty-color: #777;--re-data-grid-loading-color: #444;--re-data-grid-loading-surface: rgba(255, 255, 255, .5);--re-data-grid-scrollbar-size: 10px;--re-data-grid-scrollbar-offset: 2px;--re-data-grid-scrollbar-thumb-size: 8px;--re-data-grid-scrollbar-thumb-color: rgba(0, 0, 0, .35);--re-data-grid-scrollbar-thumb-rounded: 4px;--re-data-grid-header-height: 40px;--re-data-grid-header-separator-color: #ccc;--re-data-grid-header-separator: 1px solid var(--re-data-grid-header-separator-color);--re-data-grid-header-surface: #fff;--re-data-grid-header-cell-font-weight: 600;--re-data-grid-header-cell-font-size: .8rem;--re-data-grid-header-cell-color: #000;--re-data-grid-header-cell-surface: #fafafa;--re-data-grid-footer-separator-color: #ccc;--re-data-grid-footer-separator: 1px solid var(--re-data-grid-footer-separator-color);--re-data-grid-footer-surface: #fff;--re-data-grid-row-separator-color: #bbb;--re-data-grid-row-separator: 1px solid var(--re-data-grid-row-separator-color);--re-data-grid-row-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-column-separator-color: transparent;--re-data-grid-column-separator: 1px solid var(--re-data-grid-column-separator-color);--re-data-grid-column-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-cell-paddings: .4rem .625rem;--re-data-grid-cell-font-weight: 400;--re-data-grid-cell-font-size: .75rem;--re-data-grid-cell-color: #000;--re-data-grid-cell-surface: #fff;--re-data-grid-sticky-header-cell-surface: #fff;--re-data-grid-sticky-cell-surface: #fdfdfd;--re-data-grid-sticky-cell-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)}:host :host,:host *,:host *:before,:host *:after{box-sizing:border-box;outline:none}:host button{outline:none}.re-dg-root{position:relative;display:block;width:100%;height:var(--re-data-grid-height);max-height:var(--re-data-grid-height);border-radius:var(--re-data-grid-rounded);border:var(--re-data-grid-separator)}.re-dg-root.fill{display:flex;flex-direction:column;height:100%}.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-body{position:relative;flex:1 1 auto;min-width:0;height:var(--re-data-grid-height);border:var(--re-data-grid-separator);border-radius:var(--re-data-grid-rounded);background-color:var(--re-data-grid-surface);overflow:auto;scrollbar-width:none;-ms-overflow-style:none}.re-dg-body::-webkit-scrollbar{width:0;height:0}.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-height)}.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;right:0;cursor:default}.re-dg-cell,.re-dg-header-cell{display:flex;flex:0 0 auto;align-items:center;padding:var(--re-data-grid-cell-paddings);border-right:var(--re-data-grid-column-separator);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.re-dg-cell{width:100%;border-bottom:var(--re-data-grid-row-separator);font-weight:var(--re-data-grid-cell-font-weight);font-size:var(--re-data-grid-cell-font-size);color:var(--re-data-grid-cell-color);background-color:var(--re-data-grid-cell-surface)}.re-dg-row:nth-child(odd) .re-dg-cell{background-color:var(--re-data-grid-row-odd-surface)}.re-dg-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-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:first-child{border-radius:var(--re-data-grid-rounded) 0 0 0}.re-dg-header-cell:last-child{border-radius:0 var(--re-data-grid-rounded) 0 0}.re-dg-data-row:last-child .re-dg-cell:first-child{border-radius:0 0 0 var(--re-data-grid-rounded)}.re-dg-data-row:last-child .re-dg-cell:last-child{border-radius:0 0 var(--re-data-grid-rounded) 0}.re-dg-header-cell .re-dg-header-text{display:-webkit-box;max-height:2.4em;line-height:1.2;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.re-dg-row.re-dg-pinned>.re-dg-cell{border-bottom:var(--re-data-grid-pinned-separator);background-color:var(--re-data-grid-pinned-surface)}.re-dg-row .re-dg-header-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row .re-dg-header-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.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-empty{position:absolute;inset:0;display:flex;place-items:center;color:var(--re-data-grid-empty-color)}.re-dg-empty-text{width:100%;text-align:center}.re-dg-loader{position:absolute;inset:0;top:var(--re-data-grid-header-height);display:grid;place-items:center;background-color:var(--re-data-grid-loading-surface);color:var(--re-data-grid-loading-color);z-index:5}.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"] }] });
1821
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
1822
+ 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 }, 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 }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, pageStartFromZero: { classPropertyName: "pageStartFromZero", publicName: "pageStartFromZero", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", sortChange: "sortChange", selectChange: "selectChange", rowClick: "rowClick", cellClick: "cellClick" }, providers: [DataGridVm], queries: [{ propertyName: "cellTypedSlotRefs", predicate: DataGridTypeCellTemplateDirective, isSignal: true }, { propertyName: "cellDataSlotRefs", predicate: DataGridCellTemplateDirective, 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 }], 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 }], ngImport: i0, template: "@let items = data();\n@let empty = !loading() && !items?.length;\n@let notEmpty = !!items?.length;\n\n@let pinnedTopH = vm.pinnedTop().length * rowHeight();\n@let pinnedBottomH = vm.pinnedBottom().length * rowHeight();\n\n<div\n #root\n class=\"re-dg-root\"\n [class.loading]=\"loading()\"\n [style.height]=\"styleHeight()\"\n role=\"table\"\n>\n @if (loading()) {\n <div class=\"re-dg-loader\">\n @let loadingTemplate = loadingTpl();\n\n @if (loadingTemplate?.tpl) {\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\n } @else {\n <span class=\"re-dg-loader-text\">\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026</span>\n }\n </div>\n }\n\n <div\n #scroll\n class=\"re-dg-body\"\n role=\"rowgroup\"\n (mouseenter)=\"showScrollbar()\"\n (mouseleave)=\"hideScrollbarSoon()\"\n >\n <div class=\"re-dg-header\" role=\"rowgroup\">\n <div #header class=\"re-dg-row re-dg-header-row\" role=\"row\">\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-header-cell\"\n role=\"columnheader\"\n [class.sortable]=\"!!col.sortKey\"\n [class.active-sort]=\"currentSortField && (currentSortField === col.sortKey)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [style.min-width.px]=\"col.minWidth || null\"\n [style.max-width.px]=\"col.maxWidth || null\"\n [style.justify-content]=\"col.align || 'left'\"\n [attr.aria-sort]=\"ariaSort(col)\"\n [attr.tabindex]=\"col.sortKey ? 0 : -1\"\n [title]=\"col.header\"\n (click)=\"col.sortKey && onSort(col)\"\n (keydown.enter)=\"col.sortKey && onSort(col)\"\n >\n @if (col.headerTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"col.headerTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: col.header }\"\n />\n } @else {\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n @let isMultiSelect = selection().mode === 'multi';\n\n @if (isCheckbox && isMultiSelect) {\n <re-checkbox-ic [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\n } @else {\n <span class=\"re-dg-header-text\">{{ col.header }}</span>\n }\n\n @if (col.sortKey) {\n <span class=\"re-dg-sort-ind\">\n @let direction = currentSortField === col.sortKey ? currentSortOrder : undefined;\n\n @if (sortTpl()) {\n <ng-container\n [ngTemplateOutlet]=\"sortTpl()!.tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: direction }\"\n />\n } @else {\n <re-sort-ic [direction]=\"direction\" />\n }\n </span>\n }\n\n @if (isExpandable(col)) {\n <button (click)=\"$event.stopPropagation(); onExpand(col)\">\n @let expanded = expanderMap().get(col.key);\n\n @if (expanderTpl()) {\n <ng-container\n [ngTemplateOutlet]=\"expanderTpl()!.tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: expanded }\" />\n } @else {\n <re-expand-ic [expanded]=\"expanded\" />\n }\n </button>\n }\n }\n </div>\n }\n </div>\n\n <!-- PINNED TOP ROWS -->\n @if (notEmpty) {\n @for (pr of vm.pinnedTop(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-top\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n }\n </div>\n\n @if (empty) {\n @let emptyTemplate = emptyTpl()?.tpl;\n\n <div class=\"re-dg-empty\">\n @if (emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"emptyTemplate\" />\n } @else {\n <span class=\"re-dg-empty-text\">\u041D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445</span>\n }\n </div>\n }\n\n <!-- Content -->\n @if (notEmpty) {\n <div class=\"re-dg-spacer\" [style.height.px]=\"items.length * rowHeight() - pinnedBottomH\"></div>\n\n @for (row of visibleRows(); track trackByRow(row); let vi = $index) {\n <div\n class=\"re-dg-row re-dg-data-row\"\n role=\"row\"\n [style.height.px]=\"rowHeight()\"\n [style.top.px]=\"(startIndex + vi) * rowHeight() + pinnedTopH + headerHeight()\"\n [attr.tabindex]=\"0\"\n (click)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n >\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.expanded]=\"!!col.expandBy\"\n [class]=\"cellClass(col, row)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.text-align]=\"col.align || 'left'\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [attr.tabindex]=\"0\"\n (click)=\"onCellClick(row, col, startIndex + vi);\"\n (keydown.enter)=\"onCellClick(row, col, startIndex + vi)\"\n >\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n\n @if (isCheckbox) {\n <re-checkbox-ic [state]=\"selector.isSelected(row)\" />\n } @else {\n <re-data-grid-cell [index]=\"startIndex + vi\" [item]=\"row\" [column]=\"col\" />\n }\n </div>\n }\n </div>\n }\n }\n\n <!-- PINNED BOTTOM ROWS -->\n @if (notEmpty) {\n <div class=\"re-dg-footer\" role=\"rowgroup\">\n @for (pr of vm.pinnedBottom(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-bottom\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Overlay scrollbar -->\n <div class=\"re-dg-scrollbar\" [class.visible]=\"vm.scrollbarVisible()\">\n <div\n class=\"re-dg-scrollbar-thumb\"\n role=\"scrollbar\"\n aria-orientation=\"vertical\"\n aria-hidden=\"false\"\n [style.height.px]=\"vm.thumbHeightPx()\"\n [style.transform]=\"'translateY(' + vm.thumbTopPx() + 'px)'\"\n (mousedown)=\"onThumbDown($event)\"\n ></div>\n </div>\n</div>\n\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-primary, #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-scrollbar-size: 10px;--re-data-grid-scrollbar-offset: 2px;--re-data-grid-scrollbar-thumb-size: 8px;--re-data-grid-scrollbar-thumb-color: rgba(0, 0, 0, .35);--re-data-grid-scrollbar-thumb-rounded: 4px;--re-data-grid-header-height: 40px;--re-data-grid-header-separator-color: #ccc;--re-data-grid-header-separator: 1px solid var(--re-data-grid-header-separator-color);--re-data-grid-header-surface: #fff;--re-data-grid-header-cell-font-weight: 600;--re-data-grid-header-cell-font-size: .8rem;--re-data-grid-header-cell-color: #000;--re-data-grid-header-cell-surface: #fafafa;--re-data-grid-footer-separator-color: #ccc;--re-data-grid-footer-separator: 1px solid var(--re-data-grid-footer-separator-color);--re-data-grid-footer-surface: #fff;--re-data-grid-row-separator-color: #bbb;--re-data-grid-row-separator: 1px solid var(--re-data-grid-row-separator-color);--re-data-grid-row-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-column-separator-color: transparent;--re-data-grid-column-separator: 1px solid var(--re-data-grid-column-separator-color);--re-data-grid-column-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-cell-paddings: .4rem .625rem;--re-data-grid-cell-font-weight: 400;--re-data-grid-cell-font-size: .75rem;--re-data-grid-cell-color: #000;--re-data-grid-cell-surface: #fff;--re-data-grid-sticky-header-cell-surface: #fff;--re-data-grid-sticky-cell-surface: #fdfdfd;--re-data-grid-sticky-cell-left-shadow: 2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-sticky-cell-right-shadow: -2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-pinned-surface: #fcfcfc;--re-data-grid-pinned-separator-color: #eee;--re-data-grid-pinned-separator: 1px solid var(--re-data-grid-pinned-separator-color);--re-data-grid-expander-color: var(--primary-color, currentColor);--re-data-grid-expanded-color: var(--re-data-grid-cell-color, #000);--re-data-grid-expanded-surface: var(--re-data-grid-cell-surface, #fff);display:block;min-height:0}: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-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-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:none;-ms-overflow-style:none}.re-dg-body::-webkit-scrollbar{width:0;height:0}.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-height)}.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;right:0;cursor:default}.re-dg-cell,.re-dg-header-cell{display:flex;flex:0 0 auto;align-items:center;padding:var(--re-data-grid-cell-paddings);border-right:var(--re-data-grid-column-separator);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.re-dg-cell{width:100%;border-bottom:var(--re-data-grid-row-separator);font-weight:var(--re-data-grid-cell-font-weight);font-size:var(--re-data-grid-cell-font-size);color:var(--re-data-grid-cell-color);background-color:var(--re-data-grid-cell-surface)}.re-dg-row:nth-child(odd) .re-dg-cell{background-color:var(--re-data-grid-row-odd-surface)}.re-dg-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-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:first-child{border-radius:var(--re-data-grid-rounded) 0 0 0}.re-dg-header-cell:last-child{border-radius:0 var(--re-data-grid-rounded) 0 0}.re-dg-data-row:last-child .re-dg-cell:first-child{border-radius:0 0 0 var(--re-data-grid-rounded)}.re-dg-data-row:last-child .re-dg-cell:last-child{border-radius:0 0 var(--re-data-grid-rounded) 0}.re-dg-header-cell .re-dg-header-text{display:-webkit-box;max-height:2.4em;line-height:1.2;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.re-dg-row.re-dg-pinned>.re-dg-cell{border-bottom:var(--re-data-grid-pinned-separator);background-color:var(--re-data-grid-pinned-surface)}.re-dg-row .re-dg-header-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row .re-dg-header-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.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-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-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"] }] });
939
1823
  }
940
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGrid, decorators: [{
1824
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGrid, decorators: [{
941
1825
  type: Component,
942
- args: [{ selector: 're-data-grid', imports: [NgTemplateOutlet, DataGridCellComponent, SortIcon, ExpandIcon, CheckboxIcon], providers: [DataGridVm], template: "@let items = data();\n@let empty = !loading() && !items?.length;\n@let notEmpty = !!items?.length;\n\n@let pinnedTopH = vm.pinnedTop().length * rowHeight();\n@let pinnedBottomH = vm.pinnedBottom().length * rowHeight();\n\n<div\n #root\n class=\"re-dg-root\"\n [class.fill]=\"fillHeight()\"\n [class.loading]=\"loading()\"\n [style.height]=\"styleHeight\"\n role=\"table\"\n>\n @if (loading()) {\n <div class=\"re-dg-loader\">\n @let loadingTemplate = loadingTpl();\n\n @if (loadingTemplate?.tpl) {\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\n } @else {\n <span class=\"re-dg-loader-text\">\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026</span>\n }\n </div>\n }\n\n <div\n #scroll\n class=\"re-dg-body\"\n role=\"rowgroup\"\n (mouseenter)=\"showScrollbar()\"\n (mouseleave)=\"hideScrollbarSoon()\"\n >\n <div class=\"re-dg-header\" role=\"rowgroup\">\n <div #header class=\"re-dg-row re-dg-header-row\" role=\"row\">\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-header-cell\"\n role=\"columnheader\"\n [class.sortable]=\"!!col.sortKey\"\n [class.active-sort]=\"currentSortField && (currentSortField === col.sortKey)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [style.min-width.px]=\"col.minWidth || null\"\n [style.max-width.px]=\"col.maxWidth || null\"\n [style.justify-content]=\"col.align || 'left'\"\n [attr.aria-sort]=\"ariaSort(col)\"\n [attr.tabindex]=\"col.sortKey ? 0 : -1\"\n [title]=\"col.header\"\n (click)=\"col.sortKey && onSort(col)\"\n (keydown.enter)=\"col.sortKey && onSort(col)\"\n >\n {{currentSortField }} {{ col.sortKey}}\n @if (col.headerTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"col.headerTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: col.header }\"\n />\n } @else {\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n @let isMultiSelect = selection().mode === 'multi';\n\n @if (isCheckbox && isMultiSelect) {\n <re-checkbox-ic mixable [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\n } @else {\n <span class=\"re-dg-header-text\">{{ col.header }}</span>\n }\n\n @if (col.sortKey) {\n <span class=\"re-dg-sort-ind\">\n <re-sort-ic [direction]=\"currentSortField === col.sortKey ? currentSortOrder : 'desc'\" />\n </span>\n }\n\n @if (isExpandable(col)) {\n <button (click)=\"$event.stopPropagation(); onExpand(col)\">\n <re-expand-ic [expanded]=\"expanderMap().get(col.key)\" />\n </button>\n }\n }\n </div>\n }\n </div>\n\n <!-- PINNED TOP ROWS -->\n @if (notEmpty) {\n @for (pr of vm.pinnedTop(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-top\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n }\n </div>\n\n @if (empty) {\n @let emptyTemplate = emptyTpl()?.tpl;\n\n <div class=\"re-dg-empty\">\n @if (emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"emptyTemplate\" />\n } @else {\n <span class=\"re-dg-empty-text\">\u041D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445</span>\n }\n </div>\n }\n\n <!-- Content -->\n @if (notEmpty) {\n <div class=\"re-dg-spacer\" [style.height.px]=\"items.length * rowHeight() - pinnedBottomH\"></div>\n\n @for (row of visibleRows(); track trackByRow(row); let vi = $index) {\n <div\n class=\"re-dg-row re-dg-data-row\"\n role=\"row\"\n [style.height.px]=\"rowHeight()\"\n [style.top.px]=\"(startIndex + vi) * rowHeight() + pinnedTopH + headerHeight()\"\n [attr.tabindex]=\"0\"\n (click)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n >\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class]=\"cellClass(col, row)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.text-align]=\"col.align || 'left'\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [attr.tabindex]=\"0\"\n (click)=\"onCellClick(row, col, startIndex + vi);\"\n (keydown.enter)=\"onCellClick(row, col, startIndex + vi)\"\n >\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n\n @if (isCheckbox) {\n <re-checkbox-ic mixable=\"false\" [state]=\"selector.isSelected(row)\" />\n } @else {\n <re-data-grid-cell [index]=\"startIndex + vi\" [item]=\"row\" [column]=\"col\" />\n }\n </div>\n }\n </div>\n }\n }\n\n <!-- PINNED BOTTOM ROWS -->\n @if (notEmpty) {\n <div class=\"re-dg-footer\" role=\"rowgroup\">\n @for (pr of vm.pinnedBottom(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-bottom\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Overlay scrollbar -->\n <div class=\"re-dg-scrollbar\" [class.visible]=\"vm.scrollbarVisible()\">\n <div\n class=\"re-dg-scrollbar-thumb\"\n role=\"scrollbar\"\n aria-orientation=\"vertical\"\n aria-hidden=\"false\"\n [style.height.px]=\"vm.thumbHeightPx()\"\n [style.transform]=\"'translateY(' + vm.thumbTopPx() + 'px)'\"\n (mousedown)=\"onThumbDown($event)\"\n ></div>\n </div>\n</div>\n", styles: [":host{--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: #fff;--re-data-grid-active: #2a90f4;--re-data-grid-empty-color: #777;--re-data-grid-loading-color: #444;--re-data-grid-loading-surface: rgba(255, 255, 255, .5);--re-data-grid-scrollbar-size: 10px;--re-data-grid-scrollbar-offset: 2px;--re-data-grid-scrollbar-thumb-size: 8px;--re-data-grid-scrollbar-thumb-color: rgba(0, 0, 0, .35);--re-data-grid-scrollbar-thumb-rounded: 4px;--re-data-grid-header-height: 40px;--re-data-grid-header-separator-color: #ccc;--re-data-grid-header-separator: 1px solid var(--re-data-grid-header-separator-color);--re-data-grid-header-surface: #fff;--re-data-grid-header-cell-font-weight: 600;--re-data-grid-header-cell-font-size: .8rem;--re-data-grid-header-cell-color: #000;--re-data-grid-header-cell-surface: #fafafa;--re-data-grid-footer-separator-color: #ccc;--re-data-grid-footer-separator: 1px solid var(--re-data-grid-footer-separator-color);--re-data-grid-footer-surface: #fff;--re-data-grid-row-separator-color: #bbb;--re-data-grid-row-separator: 1px solid var(--re-data-grid-row-separator-color);--re-data-grid-row-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-column-separator-color: transparent;--re-data-grid-column-separator: 1px solid var(--re-data-grid-column-separator-color);--re-data-grid-column-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-cell-paddings: .4rem .625rem;--re-data-grid-cell-font-weight: 400;--re-data-grid-cell-font-size: .75rem;--re-data-grid-cell-color: #000;--re-data-grid-cell-surface: #fff;--re-data-grid-sticky-header-cell-surface: #fff;--re-data-grid-sticky-cell-surface: #fdfdfd;--re-data-grid-sticky-cell-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)}:host :host,:host *,:host *:before,:host *:after{box-sizing:border-box;outline:none}:host button{outline:none}.re-dg-root{position:relative;display:block;width:100%;height:var(--re-data-grid-height);max-height:var(--re-data-grid-height);border-radius:var(--re-data-grid-rounded);border:var(--re-data-grid-separator)}.re-dg-root.fill{display:flex;flex-direction:column;height:100%}.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-body{position:relative;flex:1 1 auto;min-width:0;height:var(--re-data-grid-height);border:var(--re-data-grid-separator);border-radius:var(--re-data-grid-rounded);background-color:var(--re-data-grid-surface);overflow:auto;scrollbar-width:none;-ms-overflow-style:none}.re-dg-body::-webkit-scrollbar{width:0;height:0}.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-height)}.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;right:0;cursor:default}.re-dg-cell,.re-dg-header-cell{display:flex;flex:0 0 auto;align-items:center;padding:var(--re-data-grid-cell-paddings);border-right:var(--re-data-grid-column-separator);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.re-dg-cell{width:100%;border-bottom:var(--re-data-grid-row-separator);font-weight:var(--re-data-grid-cell-font-weight);font-size:var(--re-data-grid-cell-font-size);color:var(--re-data-grid-cell-color);background-color:var(--re-data-grid-cell-surface)}.re-dg-row:nth-child(odd) .re-dg-cell{background-color:var(--re-data-grid-row-odd-surface)}.re-dg-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-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:first-child{border-radius:var(--re-data-grid-rounded) 0 0 0}.re-dg-header-cell:last-child{border-radius:0 var(--re-data-grid-rounded) 0 0}.re-dg-data-row:last-child .re-dg-cell:first-child{border-radius:0 0 0 var(--re-data-grid-rounded)}.re-dg-data-row:last-child .re-dg-cell:last-child{border-radius:0 0 var(--re-data-grid-rounded) 0}.re-dg-header-cell .re-dg-header-text{display:-webkit-box;max-height:2.4em;line-height:1.2;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.re-dg-row.re-dg-pinned>.re-dg-cell{border-bottom:var(--re-data-grid-pinned-separator);background-color:var(--re-data-grid-pinned-surface)}.re-dg-row .re-dg-header-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row .re-dg-header-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.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-empty{position:absolute;inset:0;display:flex;place-items:center;color:var(--re-data-grid-empty-color)}.re-dg-empty-text{width:100%;text-align:center}.re-dg-loader{position:absolute;inset:0;top:var(--re-data-grid-header-height);display:grid;place-items:center;background-color:var(--re-data-grid-loading-surface);color:var(--re-data-grid-loading-color);z-index:5}.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"] }]
943
- }], 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 }] }], 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 }] }], fillHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillHeight", required: false }] }], virtualBuffer: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualBuffer", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], pageStartFromZero: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageStartFromZero", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], selectChange: [{ type: i0.Output, args: ["selectChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], rootEl: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }], scrollEl: [{ type: i0.ViewChild, args: ['scroll', { isSignal: true }] }], headerEl: [{ type: i0.ViewChild, args: ['header', { isSignal: true }] }], cellSlotRefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DataGridTypeCellTemplateDirective), { 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 }] }] } });
1826
+ args: [{ selector: 're-data-grid', imports: [NgTemplateOutlet, DataGridCellComponent, SortIcon, ExpandIcon, CheckboxIcon], providers: [DataGridVm], template: "@let items = data();\n@let empty = !loading() && !items?.length;\n@let notEmpty = !!items?.length;\n\n@let pinnedTopH = vm.pinnedTop().length * rowHeight();\n@let pinnedBottomH = vm.pinnedBottom().length * rowHeight();\n\n<div\n #root\n class=\"re-dg-root\"\n [class.loading]=\"loading()\"\n [style.height]=\"styleHeight()\"\n role=\"table\"\n>\n @if (loading()) {\n <div class=\"re-dg-loader\">\n @let loadingTemplate = loadingTpl();\n\n @if (loadingTemplate?.tpl) {\n <ng-container [ngTemplateOutlet]=\"loadingTemplate!.tpl\" />\n } @else {\n <span class=\"re-dg-loader-text\">\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026</span>\n }\n </div>\n }\n\n <div\n #scroll\n class=\"re-dg-body\"\n role=\"rowgroup\"\n (mouseenter)=\"showScrollbar()\"\n (mouseleave)=\"hideScrollbarSoon()\"\n >\n <div class=\"re-dg-header\" role=\"rowgroup\">\n <div #header class=\"re-dg-row re-dg-header-row\" role=\"row\">\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-header-cell\"\n role=\"columnheader\"\n [class.sortable]=\"!!col.sortKey\"\n [class.active-sort]=\"currentSortField && (currentSortField === col.sortKey)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [style.min-width.px]=\"col.minWidth || null\"\n [style.max-width.px]=\"col.maxWidth || null\"\n [style.justify-content]=\"col.align || 'left'\"\n [attr.aria-sort]=\"ariaSort(col)\"\n [attr.tabindex]=\"col.sortKey ? 0 : -1\"\n [title]=\"col.header\"\n (click)=\"col.sortKey && onSort(col)\"\n (keydown.enter)=\"col.sortKey && onSort(col)\"\n >\n @if (col.headerTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"col.headerTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: col.header }\"\n />\n } @else {\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n @let isMultiSelect = selection().mode === 'multi';\n\n @if (isCheckbox && isMultiSelect) {\n <re-checkbox-ic [state]=\"selector.isAllSelected()\" (click)=\"selector.selectAll()\" />\n } @else {\n <span class=\"re-dg-header-text\">{{ col.header }}</span>\n }\n\n @if (col.sortKey) {\n <span class=\"re-dg-sort-ind\">\n @let direction = currentSortField === col.sortKey ? currentSortOrder : undefined;\n\n @if (sortTpl()) {\n <ng-container\n [ngTemplateOutlet]=\"sortTpl()!.tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: direction }\"\n />\n } @else {\n <re-sort-ic [direction]=\"direction\" />\n }\n </span>\n }\n\n @if (isExpandable(col)) {\n <button (click)=\"$event.stopPropagation(); onExpand(col)\">\n @let expanded = expanderMap().get(col.key);\n\n @if (expanderTpl()) {\n <ng-container\n [ngTemplateOutlet]=\"expanderTpl()!.tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: expanded }\" />\n } @else {\n <re-expand-ic [expanded]=\"expanded\" />\n }\n </button>\n }\n }\n </div>\n }\n </div>\n\n <!-- PINNED TOP ROWS -->\n @if (notEmpty) {\n @for (pr of vm.pinnedTop(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-top\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n }\n </div>\n\n @if (empty) {\n @let emptyTemplate = emptyTpl()?.tpl;\n\n <div class=\"re-dg-empty\">\n @if (emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"emptyTemplate\" />\n } @else {\n <span class=\"re-dg-empty-text\">\u041D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445</span>\n }\n </div>\n }\n\n <!-- Content -->\n @if (notEmpty) {\n <div class=\"re-dg-spacer\" [style.height.px]=\"items.length * rowHeight() - pinnedBottomH\"></div>\n\n @for (row of visibleRows(); track trackByRow(row); let vi = $index) {\n <div\n class=\"re-dg-row re-dg-data-row\"\n role=\"row\"\n [style.height.px]=\"rowHeight()\"\n [style.top.px]=\"(startIndex + vi) * rowHeight() + pinnedTopH + headerHeight()\"\n [attr.tabindex]=\"0\"\n (click)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n (keydown.enter)=\"$event.stopPropagation(); rowClick.emit({ row, index: startIndex + vi })\"\n >\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.expanded]=\"!!col.expandBy\"\n [class]=\"cellClass(col, row)\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.text-align]=\"col.align || 'left'\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n [attr.tabindex]=\"0\"\n (click)=\"onCellClick(row, col, startIndex + vi);\"\n (keydown.enter)=\"onCellClick(row, col, startIndex + vi)\"\n >\n @let isCheckbox = 'type' in col && col.type === 'checkbox';\n\n @if (isCheckbox) {\n <re-checkbox-ic [state]=\"selector.isSelected(row)\" />\n } @else {\n <re-data-grid-cell [index]=\"startIndex + vi\" [item]=\"row\" [column]=\"col\" />\n }\n </div>\n }\n </div>\n }\n }\n\n <!-- PINNED BOTTOM ROWS -->\n @if (notEmpty) {\n <div class=\"re-dg-footer\" role=\"rowgroup\">\n @for (pr of vm.pinnedBottom(); track trackPinnedRow(pr)) {\n <div class=\"re-dg-row re-dg-pinned re-dg-bottom\" role=\"row\">\n @if (pr.rowTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"pr.rowTemplate!\"\n [ngTemplateOutletContext]=\"{ $implicit: resolvePinnedData(pr) }\"\n />\n } @else {\n @for (col of vm.columnsToShow(); track col.key) {\n <div\n class=\"re-dg-cell\"\n role=\"cell\"\n [class.sticky-left]=\"vm.isStickyLeft(col.key)\"\n [class.sticky-right]=\"vm.isStickyRight(col.key)\"\n [style.left.px]=\"vm.stickyOffset(col.key, 'left')\"\n [style.right.px]=\"vm.stickyOffset(col.key, 'right')\"\n [style.justify-items]=\"col.align || 'left'\"\n [style.height.px]=\"rowHeight()\"\n [style.width.px]=\"vm.widthByKey(col.key)\"\n >\n {{ resolvePinnedData(pr)[col.key] ?? '' }}\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Overlay scrollbar -->\n <div class=\"re-dg-scrollbar\" [class.visible]=\"vm.scrollbarVisible()\">\n <div\n class=\"re-dg-scrollbar-thumb\"\n role=\"scrollbar\"\n aria-orientation=\"vertical\"\n aria-hidden=\"false\"\n [style.height.px]=\"vm.thumbHeightPx()\"\n [style.transform]=\"'translateY(' + vm.thumbTopPx() + 'px)'\"\n (mousedown)=\"onThumbDown($event)\"\n ></div>\n </div>\n</div>\n\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-primary, #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-scrollbar-size: 10px;--re-data-grid-scrollbar-offset: 2px;--re-data-grid-scrollbar-thumb-size: 8px;--re-data-grid-scrollbar-thumb-color: rgba(0, 0, 0, .35);--re-data-grid-scrollbar-thumb-rounded: 4px;--re-data-grid-header-height: 40px;--re-data-grid-header-separator-color: #ccc;--re-data-grid-header-separator: 1px solid var(--re-data-grid-header-separator-color);--re-data-grid-header-surface: #fff;--re-data-grid-header-cell-font-weight: 600;--re-data-grid-header-cell-font-size: .8rem;--re-data-grid-header-cell-color: #000;--re-data-grid-header-cell-surface: #fafafa;--re-data-grid-footer-separator-color: #ccc;--re-data-grid-footer-separator: 1px solid var(--re-data-grid-footer-separator-color);--re-data-grid-footer-surface: #fff;--re-data-grid-row-separator-color: #bbb;--re-data-grid-row-separator: 1px solid var(--re-data-grid-row-separator-color);--re-data-grid-row-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-column-separator-color: transparent;--re-data-grid-column-separator: 1px solid var(--re-data-grid-column-separator-color);--re-data-grid-column-odd-surface: var(--re-data-grid-cell-surface);--re-data-grid-cell-paddings: .4rem .625rem;--re-data-grid-cell-font-weight: 400;--re-data-grid-cell-font-size: .75rem;--re-data-grid-cell-color: #000;--re-data-grid-cell-surface: #fff;--re-data-grid-sticky-header-cell-surface: #fff;--re-data-grid-sticky-cell-surface: #fdfdfd;--re-data-grid-sticky-cell-left-shadow: 2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-sticky-cell-right-shadow: -2px 0 2px rgba(0, 0, 0, .03);--re-data-grid-pinned-surface: #fcfcfc;--re-data-grid-pinned-separator-color: #eee;--re-data-grid-pinned-separator: 1px solid var(--re-data-grid-pinned-separator-color);--re-data-grid-expander-color: var(--primary-color, currentColor);--re-data-grid-expanded-color: var(--re-data-grid-cell-color, #000);--re-data-grid-expanded-surface: var(--re-data-grid-cell-surface, #fff);display:block;min-height:0}: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-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-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:none;-ms-overflow-style:none}.re-dg-body::-webkit-scrollbar{width:0;height:0}.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-height)}.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;right:0;cursor:default}.re-dg-cell,.re-dg-header-cell{display:flex;flex:0 0 auto;align-items:center;padding:var(--re-data-grid-cell-paddings);border-right:var(--re-data-grid-column-separator);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.re-dg-cell{width:100%;border-bottom:var(--re-data-grid-row-separator);font-weight:var(--re-data-grid-cell-font-weight);font-size:var(--re-data-grid-cell-font-size);color:var(--re-data-grid-cell-color);background-color:var(--re-data-grid-cell-surface)}.re-dg-row:nth-child(odd) .re-dg-cell{background-color:var(--re-data-grid-row-odd-surface)}.re-dg-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-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:first-child{border-radius:var(--re-data-grid-rounded) 0 0 0}.re-dg-header-cell:last-child{border-radius:0 var(--re-data-grid-rounded) 0 0}.re-dg-data-row:last-child .re-dg-cell:first-child{border-radius:0 0 0 var(--re-data-grid-rounded)}.re-dg-data-row:last-child .re-dg-cell:last-child{border-radius:0 0 var(--re-data-grid-rounded) 0}.re-dg-header-cell .re-dg-header-text{display:-webkit-box;max-height:2.4em;line-height:1.2;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.re-dg-row.re-dg-pinned>.re-dg-cell{border-bottom:var(--re-data-grid-pinned-separator);background-color:var(--re-data-grid-pinned-surface)}.re-dg-row .re-dg-header-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-left{box-shadow:var(--re-data-grid-sticky-cell-left-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.re-dg-row .re-dg-header-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-header-cell-surface)}.re-dg-row .re-dg-cell.sticky-right{box-shadow:var(--re-data-grid-sticky-cell-right-shadow);background-color:var(--re-data-grid-sticky-cell-surface)}.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-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-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"] }]
1827
+ }], 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 }] }], 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 }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], pageStartFromZero: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageStartFromZero", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], selectChange: [{ type: i0.Output, args: ["selectChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], 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 }] }], 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 }] }] } });
944
1828
 
945
1829
  /**
946
1830
  * Generated bundle index. Do not edit.
947
1831
  */
948
1832
 
949
- export { DataGrid, DataGridCellEmptyDirective, DataGridCellLoadingDirective, DataGridHeaderTemplateDirective, DataGridTypeCellTemplateDirective };
1833
+ export { DataGrid, DataGridCellEmptyDirective, DataGridCellLoadingDirective, DataGridCellTemplateDirective, DataGridExpanderIconDirective, DataGridHeaderTemplateDirective, DataGridPaginator, DataGridSortIconDirective, DataGridTypeCellTemplateDirective };
950
1834
  //# sourceMappingURL=reforgium-data-grid.mjs.map