@reforgium/data-grid 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,950 @@
|
|
|
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';
|
|
3
|
+
import { NgTemplateOutlet, DatePipe, DecimalPipe } from '@angular/common';
|
|
4
|
+
import { Subscription, fromEvent, auditTime } from 'rxjs';
|
|
5
|
+
|
|
6
|
+
class DataGridTypeCellTemplateDirective {
|
|
7
|
+
type = input('', { ...(ngDevMode ? { debugName: "type" } : {}), alias: 'ssDataGridTypeCell' });
|
|
8
|
+
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 });
|
|
11
|
+
}
|
|
12
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridTypeCellTemplateDirective, decorators: [{
|
|
13
|
+
type: Directive,
|
|
14
|
+
args: [{ selector: 'ng-template[ssDataGridTypeCell]' }]
|
|
15
|
+
}], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "ssDataGridTypeCell", required: false }] }] } });
|
|
16
|
+
|
|
17
|
+
class DataGridHeaderTemplateDirective {
|
|
18
|
+
key = input('', { ...(ngDevMode ? { debugName: "key" } : {}), alias: 'ssDataGridHeader' });
|
|
19
|
+
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 });
|
|
22
|
+
}
|
|
23
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridHeaderTemplateDirective, decorators: [{
|
|
24
|
+
type: Directive,
|
|
25
|
+
args: [{ selector: 'ng-template[ssDataGridHeader]' }]
|
|
26
|
+
}], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "ssDataGridHeader", required: false }] }] } });
|
|
27
|
+
|
|
28
|
+
class DataGridCellEmptyDirective {
|
|
29
|
+
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 });
|
|
32
|
+
}
|
|
33
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellEmptyDirective, decorators: [{
|
|
34
|
+
type: Directive,
|
|
35
|
+
args: [{ selector: 'ng-template[ssDataGridEmpty]' }]
|
|
36
|
+
}] });
|
|
37
|
+
class DataGridCellLoadingDirective {
|
|
38
|
+
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 });
|
|
41
|
+
}
|
|
42
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellLoadingDirective, decorators: [{
|
|
43
|
+
type: Directive,
|
|
44
|
+
args: [{ selector: 'ng-template[ssDataGridLoading]' }]
|
|
45
|
+
}] });
|
|
46
|
+
|
|
47
|
+
const GRID_INDEX_COLUMN = {
|
|
48
|
+
key: '_index',
|
|
49
|
+
type: 'index',
|
|
50
|
+
align: 'center',
|
|
51
|
+
header: '№',
|
|
52
|
+
width: 72,
|
|
53
|
+
sticky: true,
|
|
54
|
+
};
|
|
55
|
+
const GRID_CHECKBOX_COLUMN = {
|
|
56
|
+
key: '_checkbox',
|
|
57
|
+
type: 'checkbox',
|
|
58
|
+
align: 'center',
|
|
59
|
+
header: 'checkbox',
|
|
60
|
+
width: 44,
|
|
61
|
+
sticky: true,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function layoutColumns(columns, containerWidth, defaultCol) {
|
|
65
|
+
const idx = visibleIndexes(columns);
|
|
66
|
+
const { fixedIdx, autoIdx } = splitFixed(columns, idx);
|
|
67
|
+
const fixedWidths = computeFixedWidths(columns, fixedIdx);
|
|
68
|
+
const baseAuto = computeBaseAuto(columns, autoIdx, defaultCol);
|
|
69
|
+
const sumFixed = sum(fixedWidths);
|
|
70
|
+
const sumBase = sum(baseAuto.map((w) => w.width));
|
|
71
|
+
const free = Math.max(containerWidth - sumFixed - sumBase, 0);
|
|
72
|
+
const grownAuto = distributeFree(columns, baseAuto, free); // water-fill
|
|
73
|
+
const widths = new Array(columns.length).fill(0);
|
|
74
|
+
if (containerWidth <= 0) {
|
|
75
|
+
const byKey = {};
|
|
76
|
+
for (let i = 0; i < columns.length; i++) {
|
|
77
|
+
// noinspection PointlessBooleanExpressionJS
|
|
78
|
+
columns[i].visible !== false && (byKey[columns[i].key] = 0);
|
|
79
|
+
}
|
|
80
|
+
return { widths, total: 0, byKey };
|
|
81
|
+
}
|
|
82
|
+
for (const { index, width } of fixedWidths) {
|
|
83
|
+
widths[index] = width;
|
|
84
|
+
}
|
|
85
|
+
for (const { index, width } of grownAuto) {
|
|
86
|
+
widths[index] = width;
|
|
87
|
+
}
|
|
88
|
+
roundAndFix(columns, widths, fixedIdx, autoIdx, containerWidth);
|
|
89
|
+
let total = 0;
|
|
90
|
+
const byKey = {};
|
|
91
|
+
for (const i of idx) {
|
|
92
|
+
total += widths[i];
|
|
93
|
+
byKey[columns[i].key] = widths[i];
|
|
94
|
+
}
|
|
95
|
+
return { widths, total, byKey };
|
|
96
|
+
}
|
|
97
|
+
function visibleIndexes(cols) {
|
|
98
|
+
const out = [];
|
|
99
|
+
for (let i = 0; i < cols.length; i++) {
|
|
100
|
+
// noinspection PointlessBooleanExpressionJS
|
|
101
|
+
cols[i].visible !== false && out.push(i);
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
function splitFixed(cols, visibleIdx) {
|
|
106
|
+
const fixedIdx = [];
|
|
107
|
+
const autoIdx = [];
|
|
108
|
+
for (const i of visibleIdx) {
|
|
109
|
+
cols[i].width === undefined ? autoIdx.push(i) : fixedIdx.push(i);
|
|
110
|
+
}
|
|
111
|
+
return { fixedIdx, autoIdx };
|
|
112
|
+
}
|
|
113
|
+
const computeFixedWidths = (cols, fixedIdx) => fixedIdx.map((index) => {
|
|
114
|
+
const col = cols[index];
|
|
115
|
+
const width = clamp$1(col.width, col.minWidth, col.maxWidth);
|
|
116
|
+
return { index, width };
|
|
117
|
+
});
|
|
118
|
+
const computeBaseAuto = (cols, autoIdx, def) => autoIdx.map((index) => {
|
|
119
|
+
const c = cols[index];
|
|
120
|
+
const base = clamp$1(c.minWidth ?? def, c.minWidth, c.maxWidth);
|
|
121
|
+
return { index, width: base };
|
|
122
|
+
});
|
|
123
|
+
function distributeFree(cols, base, free) {
|
|
124
|
+
if (free <= 0 || base.length === 0) {
|
|
125
|
+
return base;
|
|
126
|
+
}
|
|
127
|
+
const widths = base.map((b) => ({ ...b }));
|
|
128
|
+
let remaining = free;
|
|
129
|
+
let growable = widths.filter((w) => widthsCanGrow(cols, w.index, w.width)).map((w) => w.index);
|
|
130
|
+
while (remaining > 0 && growable.length > 0) {
|
|
131
|
+
const flexSum = growable.reduce((s, i) => s + (cols[i].flex ?? 1), 0) || 1;
|
|
132
|
+
let distributed = 0;
|
|
133
|
+
for (const i of growable) {
|
|
134
|
+
const rec = widths.find((w) => w.index === i);
|
|
135
|
+
const cap = (cols[i].maxWidth ?? Infinity) - rec.width;
|
|
136
|
+
if (cap <= 0) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const ideal = remaining * ((cols[i].flex ?? 1) / flexSum);
|
|
140
|
+
const add = ideal < cap ? ideal : cap;
|
|
141
|
+
if (add > 0) {
|
|
142
|
+
rec.width += add;
|
|
143
|
+
distributed += add;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (distributed <= 1e-6) {
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
remaining -= distributed;
|
|
150
|
+
growable = widths.filter((w) => widthsCanGrow(cols, w.index, w.width)).map((w) => w.index);
|
|
151
|
+
}
|
|
152
|
+
return widths;
|
|
153
|
+
}
|
|
154
|
+
function widthsCanGrow(cols, i, cur) {
|
|
155
|
+
const max = cols[i].maxWidth ?? Infinity;
|
|
156
|
+
return cur < max - 1e-6;
|
|
157
|
+
}
|
|
158
|
+
function roundAndFix(cols, widths, fixedIdx, autoIdx, containerWidth) {
|
|
159
|
+
const sumFixed = fixedIdx.reduce((s, i) => s + widths[i], 0);
|
|
160
|
+
let sumAuto = 0;
|
|
161
|
+
for (const i of autoIdx) {
|
|
162
|
+
widths[i] = Math.floor(widths[i]);
|
|
163
|
+
sumAuto += widths[i];
|
|
164
|
+
}
|
|
165
|
+
let need = Math.round(Math.max(containerWidth - sumFixed - sumAuto, 0));
|
|
166
|
+
if (need === 0) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
for (let k = autoIdx.length - 1; k >= 0 && need > 0; k--) {
|
|
170
|
+
const i = autoIdx[k];
|
|
171
|
+
const max = cols[i].maxWidth ?? Infinity;
|
|
172
|
+
if (widths[i] + 1 <= max) {
|
|
173
|
+
widths[i] += 1;
|
|
174
|
+
need--;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function clamp$1(v, min, max) {
|
|
179
|
+
min != null && v < min && (v = min);
|
|
180
|
+
max != null && v > max && (v = max);
|
|
181
|
+
return v;
|
|
182
|
+
}
|
|
183
|
+
function sum(items) {
|
|
184
|
+
if (Array.isArray(items) && typeof items[0] === 'number') {
|
|
185
|
+
return items.reduce((s, x) => s + x, 0);
|
|
186
|
+
}
|
|
187
|
+
return items.reduce((s, x) => s + x.width, 0);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Вычисляет визуальное состояние оверлейного скроллбара. Все аргументы - сырые DOM-числа.
|
|
192
|
+
* Возвращает состояние, описывающее видимость, размер и позицию ползунка.
|
|
193
|
+
*/
|
|
194
|
+
function computeScrollbarState(scrollHeight = 0, clientHeight = 0, scrollTop = 0, minThumb = 24) {
|
|
195
|
+
const safeClient = toSafe(clientHeight);
|
|
196
|
+
const safeScrollH = toSafe(scrollHeight);
|
|
197
|
+
const safeTop = clamp(scrollTop, 0, Math.max(0, safeScrollH - safeClient));
|
|
198
|
+
if (safeClient <= 0 || !isFinite(safeClient)) {
|
|
199
|
+
return hiddenState();
|
|
200
|
+
}
|
|
201
|
+
if (safeScrollH <= safeClient + 1) {
|
|
202
|
+
return hiddenState(safeClient);
|
|
203
|
+
}
|
|
204
|
+
const track = safeClient;
|
|
205
|
+
const ratio = track / safeScrollH;
|
|
206
|
+
const thumb = Math.max(minThumb, Math.floor(track * ratio));
|
|
207
|
+
const maxScrollTop = Math.max(1, safeScrollH - track);
|
|
208
|
+
const maxThumbTop = Math.max(1, track - thumb);
|
|
209
|
+
const topRaw = Math.round((safeTop / maxScrollTop) * maxThumbTop);
|
|
210
|
+
const thumbTop = clamp(isFinite(topRaw) ? topRaw : 0, 0, maxThumbTop);
|
|
211
|
+
return {
|
|
212
|
+
visible: true,
|
|
213
|
+
thumbHeight: thumb,
|
|
214
|
+
thumbTop,
|
|
215
|
+
track,
|
|
216
|
+
maxThumbTop,
|
|
217
|
+
maxScrollTop,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/** Преобразует позицию ползунка thumbTop (0..maxThumbTop) в позицию прокрутки scrollTop (0..maxScrollTop) */
|
|
221
|
+
function mapThumbTopToScrollTop(thumbTop, maxThumbTop, maxScrollTop) {
|
|
222
|
+
const mt = Math.max(1, toSafe(maxThumbTop));
|
|
223
|
+
const ms = Math.max(1, toSafe(maxScrollTop));
|
|
224
|
+
const tt = clamp(toSafe(thumbTop), 0, mt);
|
|
225
|
+
return (tt / mt) * ms;
|
|
226
|
+
}
|
|
227
|
+
/** Ограничивает новую позицию ползунка в пределах 0..maxThumbTop */
|
|
228
|
+
function clampThumbTop(value, maxThumbTop) {
|
|
229
|
+
const mt = Math.max(1, toSafe(maxThumbTop));
|
|
230
|
+
return clamp(toSafe(value), 0, mt);
|
|
231
|
+
}
|
|
232
|
+
function hiddenState(track = 0) {
|
|
233
|
+
return {
|
|
234
|
+
visible: false,
|
|
235
|
+
thumbHeight: 0,
|
|
236
|
+
thumbTop: 0,
|
|
237
|
+
track,
|
|
238
|
+
maxThumbTop: 1,
|
|
239
|
+
maxScrollTop: 1,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function toSafe(n) {
|
|
243
|
+
return Number.isFinite(n) ? n : 0;
|
|
244
|
+
}
|
|
245
|
+
function clamp(v, min, max) {
|
|
246
|
+
if (v < min)
|
|
247
|
+
return min;
|
|
248
|
+
if (v > max)
|
|
249
|
+
return max;
|
|
250
|
+
return v;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
class ScrollDirectionDetector {
|
|
254
|
+
el;
|
|
255
|
+
#prevTop = 0;
|
|
256
|
+
#prevLeft = 0;
|
|
257
|
+
constructor(el) {
|
|
258
|
+
this.el = el;
|
|
259
|
+
this.#prevTop = el.scrollTop;
|
|
260
|
+
this.#prevLeft = el.scrollLeft;
|
|
261
|
+
}
|
|
262
|
+
detect() {
|
|
263
|
+
const { scrollTop, scrollLeft } = this.el;
|
|
264
|
+
const deltaX = Math.abs(scrollLeft - this.#prevLeft);
|
|
265
|
+
const deltaY = Math.abs(scrollTop - this.#prevTop);
|
|
266
|
+
this.#prevTop = scrollTop;
|
|
267
|
+
this.#prevLeft = scrollLeft;
|
|
268
|
+
if (deltaX === 0 && deltaY === 0)
|
|
269
|
+
return 'none';
|
|
270
|
+
if (deltaX > deltaY)
|
|
271
|
+
return 'horizontal';
|
|
272
|
+
if (deltaY > deltaX)
|
|
273
|
+
return 'vertical';
|
|
274
|
+
return 'none';
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function splitSticky(cols) {
|
|
279
|
+
const visible = cols.filter((c) => c.visible !== false);
|
|
280
|
+
const middleIndex = Math.floor(visible.length / 2);
|
|
281
|
+
const left = visible.slice(0, middleIndex).filter((col) => col.sticky);
|
|
282
|
+
const right = visible.slice(middleIndex, visible.length).filter((col) => col.sticky);
|
|
283
|
+
return { left, right, visible };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
class DataGridVm {
|
|
287
|
+
scrollEl = signal(undefined, ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
|
|
288
|
+
columns = signal([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
289
|
+
pinnedRows = signal([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
|
|
290
|
+
containerWidth = signal(0, ...(ngDevMode ? [{ debugName: "containerWidth" }] : []));
|
|
291
|
+
scrollbarVisible = signal(false, ...(ngDevMode ? [{ debugName: "scrollbarVisible" }] : []));
|
|
292
|
+
thumbHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbHeightPx" }] : []));
|
|
293
|
+
thumbTopPx = signal(0, ...(ngDevMode ? [{ debugName: "thumbTopPx" }] : []));
|
|
294
|
+
dragging = false;
|
|
295
|
+
globalTypeCellTpls = new Map();
|
|
296
|
+
#byKey = signal({}, ...(ngDevMode ? [{ debugName: "#byKey" }] : []));
|
|
297
|
+
#defaultColWidth = 140;
|
|
298
|
+
#stickyLeftMap = new Map();
|
|
299
|
+
#stickyRightMap = new Map();
|
|
300
|
+
columnsToShow = computed(() => {
|
|
301
|
+
this.containerWidth();
|
|
302
|
+
const cols = this.columns() ?? [];
|
|
303
|
+
const { left, visible, right } = splitSticky(cols);
|
|
304
|
+
this.recomputeStickyOffsets(left, right);
|
|
305
|
+
return visible;
|
|
306
|
+
}, ...(ngDevMode ? [{ debugName: "columnsToShow" }] : []));
|
|
307
|
+
pinnedTop = computed(() => (this.pinnedRows() ?? []).filter((r) => r.position === 'top').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)), ...(ngDevMode ? [{ debugName: "pinnedTop" }] : []));
|
|
308
|
+
pinnedBottom = computed(() => (this.pinnedRows() ?? []).filter((r) => r.position === 'bottom').sort((a, b) => (a.order ?? 0) - (b.order ?? 0)), ...(ngDevMode ? [{ debugName: "pinnedBottom" }] : []));
|
|
309
|
+
constructor() {
|
|
310
|
+
effect(() => {
|
|
311
|
+
const cols = this.columns();
|
|
312
|
+
const width = this.containerWidth();
|
|
313
|
+
if (!cols.length || !width) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const res = layoutColumns(cols, width, this.#defaultColWidth);
|
|
317
|
+
this.#byKey.set(res.byKey);
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
widthByKey = (key) => this.#byKey()[key] ?? this.#defaultColWidth;
|
|
321
|
+
isStickyLeft = (key) => this.#stickyLeftMap.has(key);
|
|
322
|
+
isStickyRight = (key) => this.#stickyRightMap.has(key);
|
|
323
|
+
stickyOffset = (key, dir) => dir === 'left' && this.isStickyLeft(key)
|
|
324
|
+
? (this.#stickyLeftMap.get(key) ?? null)
|
|
325
|
+
: dir === 'right' && this.isStickyRight(key)
|
|
326
|
+
? (this.#stickyRightMap.get(key) ?? null)
|
|
327
|
+
: null;
|
|
328
|
+
calcScrollbar() {
|
|
329
|
+
const el = this.scrollEl()?.nativeElement;
|
|
330
|
+
if (!el)
|
|
331
|
+
return;
|
|
332
|
+
const state = computeScrollbarState(el.scrollHeight, el.clientHeight, el.scrollTop);
|
|
333
|
+
if (!state.visible) {
|
|
334
|
+
this.scrollbarVisible.set(false);
|
|
335
|
+
this.thumbHeightPx.set(0);
|
|
336
|
+
this.thumbTopPx.set(0);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
this.thumbHeightPx.set(state.thumbHeight);
|
|
340
|
+
this.thumbTopPx.set(state.thumbTop);
|
|
341
|
+
}
|
|
342
|
+
recomputeStickyOffsets(leftCols, rightCols) {
|
|
343
|
+
let acc = 0;
|
|
344
|
+
this.#stickyLeftMap.clear();
|
|
345
|
+
for (const col of leftCols) {
|
|
346
|
+
this.#stickyLeftMap.set(col.key, acc);
|
|
347
|
+
acc += this.widthByKey(col.key);
|
|
348
|
+
}
|
|
349
|
+
acc = 0;
|
|
350
|
+
this.#stickyRightMap.clear();
|
|
351
|
+
for (let i = rightCols.length - 1; i >= 0; i--) {
|
|
352
|
+
const col = rightCols[i];
|
|
353
|
+
this.#stickyRightMap.set(col.key, acc);
|
|
354
|
+
acc += this.widthByKey(col.key);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
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 });
|
|
359
|
+
}
|
|
360
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridVm, decorators: [{
|
|
361
|
+
type: Injectable
|
|
362
|
+
}], ctorParameters: () => [] });
|
|
363
|
+
|
|
364
|
+
class DataGridCellComponent {
|
|
365
|
+
index = input.required(...(ngDevMode ? [{ debugName: "index" }] : []));
|
|
366
|
+
item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
|
|
367
|
+
column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
|
|
368
|
+
vm = inject(DataGridVm);
|
|
369
|
+
type = computed(() => {
|
|
370
|
+
const col = this.column();
|
|
371
|
+
if ('renderTemplate' in col) {
|
|
372
|
+
return 'tpl';
|
|
373
|
+
}
|
|
374
|
+
if ('type' in col && this.vm.globalTypeCellTpls.has(col.type)) {
|
|
375
|
+
return 'globalTypeTpl';
|
|
376
|
+
}
|
|
377
|
+
return 'type' in col ? col['type'] : 'plain';
|
|
378
|
+
}, ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
379
|
+
value = computed(() => {
|
|
380
|
+
const col = this.column();
|
|
381
|
+
const row = this.item();
|
|
382
|
+
return 'value' in col ? col.value(row) : row[col.key];
|
|
383
|
+
}, ...(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: `
|
|
386
|
+
@let row = item();
|
|
387
|
+
@let col = column();
|
|
388
|
+
@let val = value();
|
|
389
|
+
|
|
390
|
+
@switch (type()) {
|
|
391
|
+
@case ('tpl') {
|
|
392
|
+
<ng-container
|
|
393
|
+
[ngTemplateOutlet]="$any(col).renderTemplate"
|
|
394
|
+
[ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index }"
|
|
395
|
+
/>
|
|
396
|
+
}
|
|
397
|
+
@case ('globalTypeTpl') {
|
|
398
|
+
<ng-container
|
|
399
|
+
[ngTemplateOutlet]="vm.globalTypeCellTpls.get($any(col).type)"
|
|
400
|
+
[ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
|
|
401
|
+
/>
|
|
402
|
+
}
|
|
403
|
+
@case ('date') {
|
|
404
|
+
{{ val | date }}
|
|
405
|
+
}
|
|
406
|
+
@case ('number') {
|
|
407
|
+
{{ val | number }}
|
|
408
|
+
}
|
|
409
|
+
@case ('index') {
|
|
410
|
+
{{ index() + 1 }}
|
|
411
|
+
}
|
|
412
|
+
@default {
|
|
413
|
+
{{ val }}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
`, 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
|
+
}
|
|
418
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGridCellComponent, decorators: [{
|
|
419
|
+
type: Component,
|
|
420
|
+
args: [{ selector: 're-data-grid-cell', template: `
|
|
421
|
+
@let row = item();
|
|
422
|
+
@let col = column();
|
|
423
|
+
@let val = value();
|
|
424
|
+
|
|
425
|
+
@switch (type()) {
|
|
426
|
+
@case ('tpl') {
|
|
427
|
+
<ng-container
|
|
428
|
+
[ngTemplateOutlet]="$any(col).renderTemplate"
|
|
429
|
+
[ngTemplateOutletContext]="{ $implicit: val, value: val, row, col, index }"
|
|
430
|
+
/>
|
|
431
|
+
}
|
|
432
|
+
@case ('globalTypeTpl') {
|
|
433
|
+
<ng-container
|
|
434
|
+
[ngTemplateOutlet]="vm.globalTypeCellTpls.get($any(col).type)"
|
|
435
|
+
[ngTemplateOutletContext]="{ $implicit: val, value: val, row, col }"
|
|
436
|
+
/>
|
|
437
|
+
}
|
|
438
|
+
@case ('date') {
|
|
439
|
+
{{ val | date }}
|
|
440
|
+
}
|
|
441
|
+
@case ('number') {
|
|
442
|
+
{{ val | number }}
|
|
443
|
+
}
|
|
444
|
+
@case ('index') {
|
|
445
|
+
{{ index() + 1 }}
|
|
446
|
+
}
|
|
447
|
+
@default {
|
|
448
|
+
{{ val }}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
`, imports: [NgTemplateOutlet, DatePipe, DecimalPipe], styles: [":host{width:100%;text-align:inherit}\n"] }]
|
|
452
|
+
}], 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
|
+
|
|
454
|
+
class Selector {
|
|
455
|
+
data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
456
|
+
selection = signal({ mode: 'none' }, ...(ngDevMode ? [{ debugName: "selection" }] : []));
|
|
457
|
+
selectedKeys = signal([], ...(ngDevMode ? [{ debugName: "selectedKeys" }] : []));
|
|
458
|
+
isAllSelected = computed(() => {
|
|
459
|
+
const selectedCount = this.selectedKeys().length;
|
|
460
|
+
return selectedCount === this.data().length ? true : selectedCount === 0 ? false : 'mixed';
|
|
461
|
+
}, ...(ngDevMode ? [{ debugName: "isAllSelected" }] : []));
|
|
462
|
+
isSelected(row) {
|
|
463
|
+
const selection = this.selection();
|
|
464
|
+
const selected = this.selectedKeys();
|
|
465
|
+
return 'key' in selection ? selected.includes(row[selection.key]) : false;
|
|
466
|
+
}
|
|
467
|
+
selectAll() {
|
|
468
|
+
if (this.selection().mode !== 'multi') {
|
|
469
|
+
throw new Error('Cannot select all in not "multi" mode');
|
|
470
|
+
}
|
|
471
|
+
const selection = this.selection();
|
|
472
|
+
const state = this.isAllSelected();
|
|
473
|
+
const nextState = state === false || state === 'mixed';
|
|
474
|
+
this.selectedKeys.set(!nextState ? [] : this.data().map((row) => row[selection.key]));
|
|
475
|
+
return this.selectedKeys();
|
|
476
|
+
}
|
|
477
|
+
select(row) {
|
|
478
|
+
if (this.selection().mode === 'none') {
|
|
479
|
+
throw new Error('Cannot select row in "none" mode');
|
|
480
|
+
}
|
|
481
|
+
const selection = this.selection();
|
|
482
|
+
if (this.selection().mode === 'single') {
|
|
483
|
+
const selected = [row[selection.key]];
|
|
484
|
+
this.selectedKeys.set(selected);
|
|
485
|
+
return selected;
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
const selectedKeys = this.selectedKeys();
|
|
489
|
+
const has = selectedKeys.some((it) => it === row[selection.key]);
|
|
490
|
+
const selected = has
|
|
491
|
+
? selectedKeys.filter((it) => it !== row[selection.key])
|
|
492
|
+
: [...selectedKeys, row[selection.key]];
|
|
493
|
+
this.selectedKeys.set(selected);
|
|
494
|
+
return selected;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// noinspection CssUnresolvedCustomProperty
|
|
500
|
+
class CheckboxIcon {
|
|
501
|
+
state = input(false, ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
502
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
503
|
+
boxRef = viewChild((ElementRef), ...(ngDevMode ? [{ debugName: "boxRef" }] : []));
|
|
504
|
+
constructor() {
|
|
505
|
+
effect(() => {
|
|
506
|
+
const el = this.boxRef()?.nativeElement;
|
|
507
|
+
if (!el) {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
const state = this.state();
|
|
511
|
+
if (state === 'mixed') {
|
|
512
|
+
el.indeterminate = true;
|
|
513
|
+
el.checked = false;
|
|
514
|
+
el.dataset.indeterminate = 'true';
|
|
515
|
+
}
|
|
516
|
+
else if (state) {
|
|
517
|
+
el.indeterminate = false;
|
|
518
|
+
el.checked = true;
|
|
519
|
+
el.dataset.indeterminate = 'false';
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
el.indeterminate = false;
|
|
523
|
+
el.checked = false;
|
|
524
|
+
el.dataset.indeterminate = 'false';
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
}
|
|
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: `
|
|
530
|
+
<label class="cb" [class.cb--disabled]="disabled()">
|
|
531
|
+
<input
|
|
532
|
+
#box
|
|
533
|
+
class="cb__input"
|
|
534
|
+
type="checkbox"
|
|
535
|
+
aria-hidden="true"
|
|
536
|
+
[disabled]="disabled()"
|
|
537
|
+
[checked]="state() === true"
|
|
538
|
+
[attr.data-indeterminate]="state() === 'mixed' ? 'true' : 'false'"
|
|
539
|
+
(click)="$event.stopPropagation()"
|
|
540
|
+
/>
|
|
541
|
+
<span class="cb__box" aria-hidden="true"></span>
|
|
542
|
+
</label>
|
|
543
|
+
`, 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
|
+
}
|
|
545
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: CheckboxIcon, decorators: [{
|
|
546
|
+
type: Component,
|
|
547
|
+
args: [{ selector: 're-checkbox-ic', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
548
|
+
<label class="cb" [class.cb--disabled]="disabled()">
|
|
549
|
+
<input
|
|
550
|
+
#box
|
|
551
|
+
class="cb__input"
|
|
552
|
+
type="checkbox"
|
|
553
|
+
aria-hidden="true"
|
|
554
|
+
[disabled]="disabled()"
|
|
555
|
+
[checked]="state() === true"
|
|
556
|
+
[attr.data-indeterminate]="state() === 'mixed' ? 'true' : 'false'"
|
|
557
|
+
(click)="$event.stopPropagation()"
|
|
558
|
+
/>
|
|
559
|
+
<span class="cb__box" aria-hidden="true"></span>
|
|
560
|
+
</label>
|
|
561
|
+
`, 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"] }]
|
|
562
|
+
}], ctorParameters: () => [], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], boxRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ElementRef), { isSignal: true }] }] } });
|
|
563
|
+
|
|
564
|
+
/* eslint-disable max-len */
|
|
565
|
+
class ExpandIcon {
|
|
566
|
+
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: `
|
|
569
|
+
@if (expanded()) {
|
|
570
|
+
<svg width="16" height="16" viewBox="0 0 16 16">
|
|
571
|
+
<path
|
|
572
|
+
d="M15.5 8C15.5 9.48336 15.0601 10.9334 14.236 12.1668C13.4119 13.4001 12.2406 14.3614 10.8701 14.9291C9.49968 15.4968 7.99168 15.6453 6.53683 15.3559C5.08197 15.0665 3.7456 14.3522 2.6967 13.3033C1.64781 12.2544 0.933503 10.918 0.644114 9.46318C0.354725 8.00832 0.50325 6.50032 1.07091 5.12987C1.63856 3.75943 2.59986 2.58809 3.83323 1.76398C5.0666 0.939867 6.51664 0.5 8 0.5C8.98492 0.5 9.96019 0.693993 10.8701 1.0709C11.7801 1.44781 12.6069 2.00026 13.3033 2.6967C13.9997 3.39314 14.5522 4.21993 14.9291 5.12987C15.306 6.03982 15.5 7.01509 15.5 8ZM12.5 8C12.5 7.80109 12.421 7.61032 12.2803 7.46967C12.1397 7.32902 11.9489 7.25 11.75 7.25H4.25C4.05109 7.25 3.86033 7.32902 3.71967 7.46967C3.57902 7.61032 3.5 7.80109 3.5 8C3.5 8.19891 3.57902 8.38968 3.71967 8.53033C3.86033 8.67098 4.05109 8.75 4.25 8.75H11.75C11.9489 8.75 12.1397 8.67098 12.2803 8.53033C12.421 8.38968 12.5 8.19891 12.5 8Z"
|
|
573
|
+
fill="var(--re-data-grid-expander-color)"
|
|
574
|
+
/>
|
|
575
|
+
</svg>
|
|
576
|
+
} @else {
|
|
577
|
+
<svg width="16" height="16" viewBox="0 0 16 16">
|
|
578
|
+
<path
|
|
579
|
+
d="M8 0.5C6.51664 0.5 5.0666 0.939867 3.83323 1.76398C2.59986 2.58809 1.63856 3.75943 1.07091 5.12987C0.50325 6.50032 0.354725 8.00832 0.644114 9.46318C0.933503 10.918 1.64781 12.2544 2.6967 13.3033C3.7456 14.3522 5.08197 15.0665 6.53683 15.3559C7.99168 15.6453 9.49968 15.4968 10.8701 14.9291C12.2406 14.3614 13.4119 13.4001 14.236 12.1668C15.0601 10.9334 15.5 9.48336 15.5 8C15.5 7.01509 15.306 6.03982 14.9291 5.12987C14.5522 4.21993 13.9997 3.39314 13.3033 2.6967C12.6069 2.00026 11.7801 1.44781 10.8701 1.0709C9.96019 0.693993 8.98492 0.5 8 0.5ZM11.75 8.75H8.75V11.75C8.75 11.9489 8.67099 12.1397 8.53033 12.2803C8.38968 12.421 8.19892 12.5 8 12.5C7.80109 12.5 7.61033 12.421 7.46967 12.2803C7.32902 12.1397 7.25 11.9489 7.25 11.75V8.75H4.25C4.05109 8.75 3.86033 8.67098 3.71967 8.53033C3.57902 8.38968 3.5 8.19891 3.5 8C3.5 7.80109 3.57902 7.61032 3.71967 7.46967C3.86033 7.32902 4.05109 7.25 4.25 7.25H7.25V4.25C7.25 4.05109 7.32902 3.86032 7.46967 3.71967C7.61033 3.57902 7.80109 3.5 8 3.5C8.19892 3.5 8.38968 3.57902 8.53033 3.71967C8.67099 3.86032 8.75 4.05109 8.75 4.25V7.25H11.75C11.9489 7.25 12.1397 7.32902 12.2803 7.46967C12.421 7.61032 12.5 7.80109 12.5 8C12.5 8.19891 12.421 8.38968 12.2803 8.53033C12.1397 8.67098 11.9489 8.75 11.75 8.75Z"
|
|
580
|
+
fill="var(--re-data-grid-expander-color)"
|
|
581
|
+
/>
|
|
582
|
+
</svg>
|
|
583
|
+
}
|
|
584
|
+
`, isInline: true, styles: [""] });
|
|
585
|
+
}
|
|
586
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ExpandIcon, decorators: [{
|
|
587
|
+
type: Component,
|
|
588
|
+
args: [{ selector: 're-expand-ic', template: `
|
|
589
|
+
@if (expanded()) {
|
|
590
|
+
<svg width="16" height="16" viewBox="0 0 16 16">
|
|
591
|
+
<path
|
|
592
|
+
d="M15.5 8C15.5 9.48336 15.0601 10.9334 14.236 12.1668C13.4119 13.4001 12.2406 14.3614 10.8701 14.9291C9.49968 15.4968 7.99168 15.6453 6.53683 15.3559C5.08197 15.0665 3.7456 14.3522 2.6967 13.3033C1.64781 12.2544 0.933503 10.918 0.644114 9.46318C0.354725 8.00832 0.50325 6.50032 1.07091 5.12987C1.63856 3.75943 2.59986 2.58809 3.83323 1.76398C5.0666 0.939867 6.51664 0.5 8 0.5C8.98492 0.5 9.96019 0.693993 10.8701 1.0709C11.7801 1.44781 12.6069 2.00026 13.3033 2.6967C13.9997 3.39314 14.5522 4.21993 14.9291 5.12987C15.306 6.03982 15.5 7.01509 15.5 8ZM12.5 8C12.5 7.80109 12.421 7.61032 12.2803 7.46967C12.1397 7.32902 11.9489 7.25 11.75 7.25H4.25C4.05109 7.25 3.86033 7.32902 3.71967 7.46967C3.57902 7.61032 3.5 7.80109 3.5 8C3.5 8.19891 3.57902 8.38968 3.71967 8.53033C3.86033 8.67098 4.05109 8.75 4.25 8.75H11.75C11.9489 8.75 12.1397 8.67098 12.2803 8.53033C12.421 8.38968 12.5 8.19891 12.5 8Z"
|
|
593
|
+
fill="var(--re-data-grid-expander-color)"
|
|
594
|
+
/>
|
|
595
|
+
</svg>
|
|
596
|
+
} @else {
|
|
597
|
+
<svg width="16" height="16" viewBox="0 0 16 16">
|
|
598
|
+
<path
|
|
599
|
+
d="M8 0.5C6.51664 0.5 5.0666 0.939867 3.83323 1.76398C2.59986 2.58809 1.63856 3.75943 1.07091 5.12987C0.50325 6.50032 0.354725 8.00832 0.644114 9.46318C0.933503 10.918 1.64781 12.2544 2.6967 13.3033C3.7456 14.3522 5.08197 15.0665 6.53683 15.3559C7.99168 15.6453 9.49968 15.4968 10.8701 14.9291C12.2406 14.3614 13.4119 13.4001 14.236 12.1668C15.0601 10.9334 15.5 9.48336 15.5 8C15.5 7.01509 15.306 6.03982 14.9291 5.12987C14.5522 4.21993 13.9997 3.39314 13.3033 2.6967C12.6069 2.00026 11.7801 1.44781 10.8701 1.0709C9.96019 0.693993 8.98492 0.5 8 0.5ZM11.75 8.75H8.75V11.75C8.75 11.9489 8.67099 12.1397 8.53033 12.2803C8.38968 12.421 8.19892 12.5 8 12.5C7.80109 12.5 7.61033 12.421 7.46967 12.2803C7.32902 12.1397 7.25 11.9489 7.25 11.75V8.75H4.25C4.05109 8.75 3.86033 8.67098 3.71967 8.53033C3.57902 8.38968 3.5 8.19891 3.5 8C3.5 7.80109 3.57902 7.61032 3.71967 7.46967C3.86033 7.32902 4.05109 7.25 4.25 7.25H7.25V4.25C7.25 4.05109 7.32902 3.86032 7.46967 3.71967C7.61033 3.57902 7.80109 3.5 8 3.5C8.19892 3.5 8.38968 3.57902 8.53033 3.71967C8.67099 3.86032 8.75 4.05109 8.75 4.25V7.25H11.75C11.9489 7.25 12.1397 7.32902 12.2803 7.46967C12.421 7.61032 12.5 7.80109 12.5 8C12.5 8.19891 12.421 8.38968 12.2803 8.53033C12.1397 8.67098 11.9489 8.75 11.75 8.75Z"
|
|
600
|
+
fill="var(--re-data-grid-expander-color)"
|
|
601
|
+
/>
|
|
602
|
+
</svg>
|
|
603
|
+
}
|
|
604
|
+
` }]
|
|
605
|
+
}], propDecorators: { expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }] } });
|
|
606
|
+
|
|
607
|
+
/* eslint-disable max-len */
|
|
608
|
+
class SortIcon {
|
|
609
|
+
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: `
|
|
612
|
+
<svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
|
|
613
|
+
<path
|
|
614
|
+
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"
|
|
615
|
+
fill="currentColor"
|
|
616
|
+
/>
|
|
617
|
+
</svg>
|
|
618
|
+
`, 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
|
+
}
|
|
620
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: SortIcon, decorators: [{
|
|
621
|
+
type: Component,
|
|
622
|
+
args: [{ selector: 're-sort-ic', template: `
|
|
623
|
+
<svg width="18" height="18" viewBox="0 0 18 18" class="{{ direction() }}">
|
|
624
|
+
<path
|
|
625
|
+
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"
|
|
626
|
+
fill="currentColor"
|
|
627
|
+
/>
|
|
628
|
+
</svg>
|
|
629
|
+
`, 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
|
+
}], propDecorators: { direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }] } });
|
|
631
|
+
|
|
632
|
+
class DataGrid {
|
|
633
|
+
/** Массив данных для отображения в таблице */
|
|
634
|
+
data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
635
|
+
/** Конфигурация колонок таблицы */
|
|
636
|
+
columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
637
|
+
/** Режим пагинации: 'none', 'pagination' или 'infinity' */
|
|
638
|
+
mode = input('none', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
639
|
+
/** Массив закрепленных строк */
|
|
640
|
+
pinnedRows = input([], ...(ngDevMode ? [{ debugName: "pinnedRows" }] : []));
|
|
641
|
+
/** Добавить ли номерную колонку */
|
|
642
|
+
hasIndexColumn = input(false, { ...(ngDevMode ? { debugName: "hasIndexColumn" } : {}), transform: booleanAttribute });
|
|
643
|
+
/** Поддержка выбора строк */
|
|
644
|
+
selection = input({ mode: 'none' }, ...(ngDevMode ? [{ debugName: "selection" }] : []));
|
|
645
|
+
/** Количество элементов на странице */
|
|
646
|
+
pageSize = input(20, { ...(ngDevMode ? { debugName: "pageSize" } : {}), transform: numberAttribute });
|
|
647
|
+
/** Высота строки в пикселях */
|
|
648
|
+
rowHeight = input(40, { ...(ngDevMode ? { debugName: "rowHeight" } : {}), transform: numberAttribute });
|
|
649
|
+
/** Заполнять ли доступную высоту */
|
|
650
|
+
fillHeight = input(true, { ...(ngDevMode ? { debugName: "fillHeight" } : {}), transform: booleanAttribute });
|
|
651
|
+
/** Размер буфера виртуального скролла */
|
|
652
|
+
virtualBuffer = input(6, ...(ngDevMode ? [{ debugName: "virtualBuffer" }] : []));
|
|
653
|
+
/** Состояние загрузки данных */
|
|
654
|
+
loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : {}), transform: booleanAttribute });
|
|
655
|
+
/** Функция или имя свойства для получения уникального ключа строки */
|
|
656
|
+
rowKey = input(undefined, ...(ngDevMode ? [{ debugName: "rowKey" }] : []));
|
|
657
|
+
/** Начинать отсчёт пагинации с 1 (false) или 0 (true) */
|
|
658
|
+
pageStartFromZero = input(true, { ...(ngDevMode ? { debugName: "pageStartFromZero" } : {}), transform: booleanAttribute });
|
|
659
|
+
/** Событие запроса данных */
|
|
660
|
+
pageChange = output();
|
|
661
|
+
/** Событие изменения сортировки */
|
|
662
|
+
sortChange = output();
|
|
663
|
+
/** Событие изменения выбранных строк */
|
|
664
|
+
selectChange = output();
|
|
665
|
+
/** Событие клика по строке */
|
|
666
|
+
rowClick = output();
|
|
667
|
+
/** Событие клика по ячейке */
|
|
668
|
+
cellClick = output();
|
|
669
|
+
vm = inject((DataGridVm));
|
|
670
|
+
selector = new Selector();
|
|
671
|
+
rootEl = viewChild('root', ...(ngDevMode ? [{ debugName: "rootEl" }] : []));
|
|
672
|
+
scrollEl = viewChild('scroll', ...(ngDevMode ? [{ debugName: "scrollEl" }] : []));
|
|
673
|
+
headerEl = viewChild('header', ...(ngDevMode ? [{ debugName: "headerEl" }] : []));
|
|
674
|
+
cellSlotRefs = contentChildren(DataGridTypeCellTemplateDirective, ...(ngDevMode ? [{ debugName: "cellSlotRefs" }] : []));
|
|
675
|
+
headerSlotRefs = contentChildren(DataGridHeaderTemplateDirective, ...(ngDevMode ? [{ debugName: "headerSlotRefs" }] : []));
|
|
676
|
+
emptySlotRefs = contentChildren(DataGridCellEmptyDirective, ...(ngDevMode ? [{ debugName: "emptySlotRefs" }] : []));
|
|
677
|
+
loadingSlotRefs = contentChildren(DataGridCellLoadingDirective, ...(ngDevMode ? [{ debugName: "loadingSlotRefs" }] : []));
|
|
678
|
+
emptyTpl = computed(() => this.emptySlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "emptyTpl" }] : []));
|
|
679
|
+
loadingTpl = computed(() => this.loadingSlotRefs()?.[0], ...(ngDevMode ? [{ debugName: "loadingTpl" }] : []));
|
|
680
|
+
visibleRows = signal([], ...(ngDevMode ? [{ debugName: "visibleRows" }] : []));
|
|
681
|
+
startIndex = 0;
|
|
682
|
+
headerHeight = signal(40, ...(ngDevMode ? [{ debugName: "headerHeight" }] : []));
|
|
683
|
+
expanderMap = signal(new Map(), ...(ngDevMode ? [{ debugName: "expanderMap" }] : []));
|
|
684
|
+
extendedColumns = computed(() => {
|
|
685
|
+
const hasSelection = this.selection().mode !== 'none';
|
|
686
|
+
const hasIndex = this.hasIndexColumn();
|
|
687
|
+
const newColumns = [];
|
|
688
|
+
hasSelection && newColumns.push(GRID_CHECKBOX_COLUMN);
|
|
689
|
+
hasIndex && newColumns.push(GRID_INDEX_COLUMN);
|
|
690
|
+
return [...newColumns, ...this.columns()];
|
|
691
|
+
}, ...(ngDevMode ? [{ debugName: "extendedColumns" }] : []));
|
|
692
|
+
hideSbTimeout;
|
|
693
|
+
currentSortField;
|
|
694
|
+
currentSortOrder = 'asc';
|
|
695
|
+
subscription = new Subscription();
|
|
696
|
+
observer;
|
|
697
|
+
constructor() {
|
|
698
|
+
afterRenderEffect(() => {
|
|
699
|
+
this.initRefs();
|
|
700
|
+
this.initHeader();
|
|
701
|
+
this.initScroll();
|
|
702
|
+
this.initObserver();
|
|
703
|
+
});
|
|
704
|
+
afterRenderEffect(() => this.initSelector());
|
|
705
|
+
afterRenderEffect(() => {
|
|
706
|
+
this.initVm();
|
|
707
|
+
this.initSort();
|
|
708
|
+
this.initExpander();
|
|
709
|
+
});
|
|
710
|
+
effect(() => {
|
|
711
|
+
this.data();
|
|
712
|
+
this.rowHeight();
|
|
713
|
+
this.pinnedRows();
|
|
714
|
+
this.vm.containerWidth();
|
|
715
|
+
this.onVerticalScroll(true);
|
|
716
|
+
});
|
|
717
|
+
effect(() => {
|
|
718
|
+
const selection = this.selection();
|
|
719
|
+
if ('defaultSelected' in selection) {
|
|
720
|
+
this.selector.selectedKeys.set(selection.defaultSelected || []);
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
inject(DestroyRef).onDestroy(() => {
|
|
724
|
+
this.subscription.unsubscribe();
|
|
725
|
+
this.observer?.disconnect();
|
|
726
|
+
clearTimeout(this.hideSbTimeout);
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
get styleHeight() {
|
|
730
|
+
return this.fillHeight() ? null : 'auto';
|
|
731
|
+
}
|
|
732
|
+
resolvePinnedData(pr) {
|
|
733
|
+
return typeof pr.data === 'function' ? pr.data() : pr.data;
|
|
734
|
+
}
|
|
735
|
+
onSort(col) {
|
|
736
|
+
if (!col.sortKey) {
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (this.currentSortField === col.sortKey) {
|
|
740
|
+
this.currentSortOrder = this.currentSortOrder === 'asc' ? 'desc' : 'asc';
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
this.currentSortField = col.sortKey;
|
|
744
|
+
this.currentSortOrder = 'asc';
|
|
745
|
+
}
|
|
746
|
+
this.sortChange.emit({ key: this.currentSortField, order: this.currentSortOrder });
|
|
747
|
+
}
|
|
748
|
+
onCellClick(row, col, index) {
|
|
749
|
+
this.cellClick.emit({ row, col, index });
|
|
750
|
+
if (this.selection().mode !== 'none') {
|
|
751
|
+
const selected = this.selector.select(row);
|
|
752
|
+
this.selectChange.emit({ selected });
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
isExpandable(column) {
|
|
756
|
+
const keys = this.expanderMap();
|
|
757
|
+
return keys.has(column.key);
|
|
758
|
+
}
|
|
759
|
+
onExpand(column) {
|
|
760
|
+
const expanded = !this.expanderMap().get(column.key);
|
|
761
|
+
this.expanderMap.update((prev) => {
|
|
762
|
+
const map = new Map(prev);
|
|
763
|
+
map.set(column.key, expanded);
|
|
764
|
+
return map;
|
|
765
|
+
});
|
|
766
|
+
const columns = this.extendedColumns().map((col) => col.expandBy === column.key ? { ...col, visible: expanded } : col);
|
|
767
|
+
this.vm.columns.set(columns);
|
|
768
|
+
}
|
|
769
|
+
onVerticalScroll(initial = false) {
|
|
770
|
+
const el = this.scrollEl()?.nativeElement;
|
|
771
|
+
if (!el)
|
|
772
|
+
return;
|
|
773
|
+
const scrollTop = el.scrollTop ?? 0;
|
|
774
|
+
const viewportHeight = el.clientHeight ?? 0;
|
|
775
|
+
const data = this.data() ?? [];
|
|
776
|
+
const total = data.length ?? 0;
|
|
777
|
+
const rowHeight = Math.max(1, this.rowHeight());
|
|
778
|
+
const virtualBuffer = Math.max(0, this.virtualBuffer());
|
|
779
|
+
const limit = this.mode() === 'pagination';
|
|
780
|
+
const cap = limit ? Math.max(1, this.pageSize()) : Number.POSITIVE_INFINITY;
|
|
781
|
+
const viewportRows = Math.ceil(viewportHeight / rowHeight);
|
|
782
|
+
const visibleCount = Math.min(viewportRows + virtualBuffer, cap);
|
|
783
|
+
const start = Math.max(0, Math.floor(scrollTop / rowHeight) - Math.floor(virtualBuffer / 2));
|
|
784
|
+
const end = Math.min(total, start + visibleCount);
|
|
785
|
+
if (!el || viewportHeight <= 0 || !isFinite(viewportHeight) || !isFinite(rowHeight)) {
|
|
786
|
+
this.visibleRows.set(data);
|
|
787
|
+
this.vm.calcScrollbar();
|
|
788
|
+
this.showScrollbar();
|
|
789
|
+
this.hideScrollbarSoon();
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
this.startIndex = start;
|
|
793
|
+
this.visibleRows.set(data.slice(start, end));
|
|
794
|
+
if (!initial && this.mode() === 'infinity') {
|
|
795
|
+
const threshold = Math.max(0, total - Math.max(1, Math.floor(visibleCount * 1.5)));
|
|
796
|
+
const nearEnd = start + visibleCount >= threshold;
|
|
797
|
+
if (nearEnd && !this.loading()) {
|
|
798
|
+
const modifier = this.pageStartFromZero() ? 0 : 1;
|
|
799
|
+
const page = Math.floor(total / this.pageSize()) + modifier;
|
|
800
|
+
this.pageChange.emit({ page, rows: this.pageSize() });
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
this.vm.calcScrollbar();
|
|
804
|
+
this.showScrollbar();
|
|
805
|
+
this.hideScrollbarSoon();
|
|
806
|
+
}
|
|
807
|
+
onHorizontalScroll() { }
|
|
808
|
+
onThumbDown(e) {
|
|
809
|
+
e.preventDefault();
|
|
810
|
+
e.stopPropagation();
|
|
811
|
+
const el = this.scrollEl()?.nativeElement;
|
|
812
|
+
if (!el)
|
|
813
|
+
return;
|
|
814
|
+
this.vm.dragging = true;
|
|
815
|
+
this.showScrollbar();
|
|
816
|
+
const startY = e.clientY;
|
|
817
|
+
const startTop = this.vm.thumbTopPx();
|
|
818
|
+
const state = computeScrollbarState(el.scrollHeight || 1, el.clientHeight || 1, el.scrollTop || 0);
|
|
819
|
+
const maxThumbTop = state.maxThumbTop || 1;
|
|
820
|
+
const maxScrollTop = state.maxScrollTop || 1;
|
|
821
|
+
const onMove = (ev) => {
|
|
822
|
+
const delta = ev.clientY - startY;
|
|
823
|
+
const newTop = clampThumbTop(startTop + delta, maxThumbTop);
|
|
824
|
+
this.vm.thumbTopPx.set(newTop);
|
|
825
|
+
el.scrollTop = mapThumbTopToScrollTop(newTop, maxThumbTop, maxScrollTop);
|
|
826
|
+
this.vm.calcScrollbar();
|
|
827
|
+
this.showScrollbar();
|
|
828
|
+
};
|
|
829
|
+
const onUp = () => {
|
|
830
|
+
window.removeEventListener('mousemove', onMove);
|
|
831
|
+
window.removeEventListener('mouseup', onUp);
|
|
832
|
+
this.vm.dragging = false;
|
|
833
|
+
this.hideScrollbarSoon();
|
|
834
|
+
};
|
|
835
|
+
window.addEventListener('mousemove', onMove);
|
|
836
|
+
window.addEventListener('mouseup', onUp);
|
|
837
|
+
}
|
|
838
|
+
showScrollbar() {
|
|
839
|
+
this.vm.scrollbarVisible.set(true);
|
|
840
|
+
clearTimeout(this.hideSbTimeout);
|
|
841
|
+
}
|
|
842
|
+
hideScrollbarSoon(delay = 1200) {
|
|
843
|
+
if (this.vm.dragging) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
clearTimeout(this.hideSbTimeout);
|
|
847
|
+
this.hideSbTimeout = setTimeout(() => this.vm.scrollbarVisible.set(false), delay);
|
|
848
|
+
}
|
|
849
|
+
// todo
|
|
850
|
+
trackPinnedRow = (row) => row.order;
|
|
851
|
+
trackByRow = (row) => {
|
|
852
|
+
const rowKey = this.rowKey();
|
|
853
|
+
if (!rowKey) {
|
|
854
|
+
return row;
|
|
855
|
+
}
|
|
856
|
+
return typeof rowKey === 'function' ? rowKey(row) : row[rowKey];
|
|
857
|
+
};
|
|
858
|
+
cellClass(col, row) {
|
|
859
|
+
if (typeof col.cellClass === 'function') {
|
|
860
|
+
return col.cellClass(row);
|
|
861
|
+
}
|
|
862
|
+
return col.cellClass;
|
|
863
|
+
}
|
|
864
|
+
ariaSort(col) {
|
|
865
|
+
if (this.currentSortField !== col.sortKey) {
|
|
866
|
+
return 'none';
|
|
867
|
+
}
|
|
868
|
+
return this.currentSortOrder === 'asc' ? 'ascending' : 'descending';
|
|
869
|
+
}
|
|
870
|
+
initVm() {
|
|
871
|
+
this.vm.scrollEl.set(this.scrollEl());
|
|
872
|
+
this.vm.columns.set(this.extendedColumns());
|
|
873
|
+
this.vm.pinnedRows.set(this.pinnedRows());
|
|
874
|
+
}
|
|
875
|
+
initSelector() {
|
|
876
|
+
this.selector.data.set(this.data());
|
|
877
|
+
this.selector.selection.set(this.selection());
|
|
878
|
+
}
|
|
879
|
+
initRefs() {
|
|
880
|
+
this.cellSlotRefs()?.forEach((dir) => this.vm.globalTypeCellTpls.set(dir.type(), dir.tpl));
|
|
881
|
+
const headerMap = new Map();
|
|
882
|
+
this.headerSlotRefs()?.forEach((h) => headerMap.set(h.key(), h.tpl));
|
|
883
|
+
this.extendedColumns()?.forEach((c) => {
|
|
884
|
+
if (!c.headerTemplate && headerMap.has(c.key)) {
|
|
885
|
+
c.headerTemplate = headerMap.get(c.key);
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
initSort() {
|
|
890
|
+
const firstSortable = this.extendedColumns()?.find((c) => !!c.sortKey);
|
|
891
|
+
if (firstSortable) {
|
|
892
|
+
this.currentSortField = firstSortable.sortKey;
|
|
893
|
+
this.currentSortOrder = 'asc';
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
initHeader() {
|
|
897
|
+
const el = this.headerEl()?.nativeElement;
|
|
898
|
+
if (!el)
|
|
899
|
+
return;
|
|
900
|
+
this.headerHeight.set(el.offsetHeight);
|
|
901
|
+
}
|
|
902
|
+
initScroll() {
|
|
903
|
+
const scrollEl = this.scrollEl()?.nativeElement;
|
|
904
|
+
if (scrollEl) {
|
|
905
|
+
const scrollDetector = new ScrollDirectionDetector(scrollEl);
|
|
906
|
+
this.subscription = fromEvent(scrollEl, 'scroll')
|
|
907
|
+
.pipe(auditTime(16))
|
|
908
|
+
.subscribe(() => {
|
|
909
|
+
const direction = scrollDetector.detect();
|
|
910
|
+
direction === 'vertical' ? this.onVerticalScroll() : this.onHorizontalScroll();
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
queueMicrotask(() => this.onVerticalScroll(true));
|
|
914
|
+
}
|
|
915
|
+
initObserver() {
|
|
916
|
+
const root = this.rootEl();
|
|
917
|
+
if (!root)
|
|
918
|
+
return;
|
|
919
|
+
this.observer = new ResizeObserver((entries) => {
|
|
920
|
+
const width = entries[0].contentRect.width;
|
|
921
|
+
this.onVerticalScroll(true);
|
|
922
|
+
this.onHorizontalScroll();
|
|
923
|
+
this.vm.calcScrollbar();
|
|
924
|
+
this.vm.containerWidth.set(width);
|
|
925
|
+
});
|
|
926
|
+
this.observer.observe(root.nativeElement);
|
|
927
|
+
}
|
|
928
|
+
initExpander() {
|
|
929
|
+
const map = new Map();
|
|
930
|
+
const columns = untracked(() => this.vm.columns().map((col) => {
|
|
931
|
+
col.expandBy && map.set(col.expandBy, false);
|
|
932
|
+
return { ...col, visible: col.expandBy ? false : col.visible };
|
|
933
|
+
}));
|
|
934
|
+
this.vm.columns.set(columns);
|
|
935
|
+
this.expanderMap.set(map);
|
|
936
|
+
}
|
|
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"] }] });
|
|
939
|
+
}
|
|
940
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DataGrid, decorators: [{
|
|
941
|
+
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 }] }] } });
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Generated bundle index. Do not edit.
|
|
947
|
+
*/
|
|
948
|
+
|
|
949
|
+
export { DataGrid, DataGridCellEmptyDirective, DataGridCellLoadingDirective, DataGridHeaderTemplateDirective, DataGridTypeCellTemplateDirective };
|
|
950
|
+
//# sourceMappingURL=reforgium-data-grid.mjs.map
|