@thkl/agrid 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -7
- package/fesm2022/thkl-agrid.mjs +918 -184
- package/fesm2022/thkl-agrid.mjs.map +1 -1
- package/package.json +4 -4
- package/types/thkl-agrid.d.ts +312 -8
- package/types/thkl-agrid.d.ts.map +1 -1
package/fesm2022/thkl-agrid.mjs
CHANGED
|
@@ -299,10 +299,16 @@ function coerceNumberInputValue(value) {
|
|
|
299
299
|
const numeric = Number(trimmed.includes('.') ? trimmed : trimmed.replace(',', '.'));
|
|
300
300
|
return Number.isNaN(numeric) ? value : numeric;
|
|
301
301
|
}
|
|
302
|
-
/** Resolve the display string for a raw cell value via ValueOption label, formatter, or coercion. */
|
|
303
|
-
function getDisplayForField(col, raw, locale) {
|
|
302
|
+
/** Resolve the display string for a raw cell value via formula, ValueOption label, formatter, or coercion. */
|
|
303
|
+
function getDisplayForField(col, raw, locale, row) {
|
|
304
304
|
if (!col)
|
|
305
305
|
return String(raw ?? '');
|
|
306
|
+
if (col.formula && typeof raw === 'string' && raw.trim().startsWith('=')) {
|
|
307
|
+
const result = evaluateFormula(raw, row ?? {});
|
|
308
|
+
if (!result.ok)
|
|
309
|
+
return '#ERR';
|
|
310
|
+
return col.formatter ? col.formatter(result.value) : formatFormulaResult(result.value);
|
|
311
|
+
}
|
|
306
312
|
if (col.values?.length) {
|
|
307
313
|
const opt = col.values.find(v => typeof v === 'string' ? v === raw : v.value === raw);
|
|
308
314
|
if (opt !== undefined)
|
|
@@ -315,6 +321,129 @@ function getDisplayForField(col, raw, locale) {
|
|
|
315
321
|
}
|
|
316
322
|
return String(raw ?? '');
|
|
317
323
|
}
|
|
324
|
+
/** Evaluate a safe row-local arithmetic formula without using `eval`. */
|
|
325
|
+
function evaluateFormula(formula, row) {
|
|
326
|
+
const source = formula.trim().startsWith('=') ? formula.trim().slice(1) : formula.trim();
|
|
327
|
+
if (!source)
|
|
328
|
+
return { ok: false, error: 'empty formula' };
|
|
329
|
+
const parser = new FormulaParser(source, row);
|
|
330
|
+
try {
|
|
331
|
+
const value = parser.parse();
|
|
332
|
+
return Number.isFinite(value) ? { ok: true, value } : { ok: false, error: 'non-finite result' };
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
return { ok: false, error: error instanceof Error ? error.message : 'invalid formula' };
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function formatFormulaResult(value) {
|
|
339
|
+
return Number.isInteger(value) ? String(value) : String(Number(value.toFixed(6)));
|
|
340
|
+
}
|
|
341
|
+
class FormulaParser {
|
|
342
|
+
source;
|
|
343
|
+
row;
|
|
344
|
+
index = 0;
|
|
345
|
+
constructor(source, row) {
|
|
346
|
+
this.source = source;
|
|
347
|
+
this.row = row;
|
|
348
|
+
}
|
|
349
|
+
parse() {
|
|
350
|
+
const value = this.expression();
|
|
351
|
+
this.skipWhitespace();
|
|
352
|
+
if (this.index < this.source.length)
|
|
353
|
+
throw new Error('unexpected token');
|
|
354
|
+
return value;
|
|
355
|
+
}
|
|
356
|
+
expression() {
|
|
357
|
+
let value = this.term();
|
|
358
|
+
while (true) {
|
|
359
|
+
this.skipWhitespace();
|
|
360
|
+
if (this.match('+'))
|
|
361
|
+
value += this.term();
|
|
362
|
+
else if (this.match('-'))
|
|
363
|
+
value -= this.term();
|
|
364
|
+
else
|
|
365
|
+
return value;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
term() {
|
|
369
|
+
let value = this.factor();
|
|
370
|
+
while (true) {
|
|
371
|
+
this.skipWhitespace();
|
|
372
|
+
if (this.match('*'))
|
|
373
|
+
value *= this.factor();
|
|
374
|
+
else if (this.match('/'))
|
|
375
|
+
value /= this.factor();
|
|
376
|
+
else
|
|
377
|
+
return value;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
factor() {
|
|
381
|
+
this.skipWhitespace();
|
|
382
|
+
if (this.match('+'))
|
|
383
|
+
return this.factor();
|
|
384
|
+
if (this.match('-'))
|
|
385
|
+
return -this.factor();
|
|
386
|
+
if (this.match('(')) {
|
|
387
|
+
const value = this.expression();
|
|
388
|
+
this.expect(')');
|
|
389
|
+
return value;
|
|
390
|
+
}
|
|
391
|
+
if (this.peek() === '[')
|
|
392
|
+
return this.bracketReference();
|
|
393
|
+
if (/[A-Za-z_]/.test(this.peek()))
|
|
394
|
+
return this.identifier();
|
|
395
|
+
return this.number();
|
|
396
|
+
}
|
|
397
|
+
number() {
|
|
398
|
+
const start = this.index;
|
|
399
|
+
while (/[0-9.]/.test(this.peek()))
|
|
400
|
+
this.index++;
|
|
401
|
+
if (start === this.index)
|
|
402
|
+
throw new Error('expected number');
|
|
403
|
+
const value = Number(this.source.slice(start, this.index));
|
|
404
|
+
if (Number.isNaN(value))
|
|
405
|
+
throw new Error('invalid number');
|
|
406
|
+
return value;
|
|
407
|
+
}
|
|
408
|
+
identifier() {
|
|
409
|
+
const start = this.index;
|
|
410
|
+
while (/[A-Za-z0-9_]/.test(this.peek()))
|
|
411
|
+
this.index++;
|
|
412
|
+
return this.referenceValue(this.source.slice(start, this.index));
|
|
413
|
+
}
|
|
414
|
+
bracketReference() {
|
|
415
|
+
this.expect('[');
|
|
416
|
+
const start = this.index;
|
|
417
|
+
while (this.peek() && this.peek() !== ']')
|
|
418
|
+
this.index++;
|
|
419
|
+
const field = this.source.slice(start, this.index);
|
|
420
|
+
this.expect(']');
|
|
421
|
+
return this.referenceValue(field);
|
|
422
|
+
}
|
|
423
|
+
referenceValue(field) {
|
|
424
|
+
const value = Number(this.row[field]);
|
|
425
|
+
if (Number.isNaN(value))
|
|
426
|
+
throw new Error(`invalid reference ${field}`);
|
|
427
|
+
return value;
|
|
428
|
+
}
|
|
429
|
+
match(char) {
|
|
430
|
+
if (this.source[this.index] !== char)
|
|
431
|
+
return false;
|
|
432
|
+
this.index++;
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
expect(char) {
|
|
436
|
+
if (!this.match(char))
|
|
437
|
+
throw new Error(`expected ${char}`);
|
|
438
|
+
}
|
|
439
|
+
peek() {
|
|
440
|
+
return this.source[this.index] ?? '';
|
|
441
|
+
}
|
|
442
|
+
skipWhitespace() {
|
|
443
|
+
while (/\s/.test(this.peek()))
|
|
444
|
+
this.index++;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
318
447
|
/** Returns whether a virtual-scroll item represents a data row. */
|
|
319
448
|
function isDataRowItem(item) {
|
|
320
449
|
return typeof item === 'object' && item !== null && 'row' in item && !('detailFor' in item);
|
|
@@ -352,14 +481,14 @@ function applyTextAndValueFilters(rows, indices, filters, colMap, locale) {
|
|
|
352
481
|
const col = colMap.get(field);
|
|
353
482
|
if (filter.text) {
|
|
354
483
|
const lc = filter.text.toLowerCase();
|
|
355
|
-
result = result.filter(i => getDisplayForField(col, rows[i][field], locale).toLowerCase().includes(lc));
|
|
484
|
+
result = result.filter(i => getDisplayForField(col, rows[i][field], locale, rows[i]).toLowerCase().includes(lc));
|
|
356
485
|
}
|
|
357
486
|
if (filter.selectedValues !== null) {
|
|
358
487
|
const allowed = new Set(filter.selectedValues);
|
|
359
488
|
result = result.filter(i => allowed.has(String(rows[i][field] ?? '')));
|
|
360
489
|
}
|
|
361
490
|
if (filter.operator && filter.operand != null && filter.operand !== '') {
|
|
362
|
-
result = result.filter(i => passesConditionFilter(col, rows[i][field], filter, locale));
|
|
491
|
+
result = result.filter(i => passesConditionFilter(col, rows[i][field], filter, locale, rows[i]));
|
|
363
492
|
}
|
|
364
493
|
}
|
|
365
494
|
return result;
|
|
@@ -367,9 +496,9 @@ function applyTextAndValueFilters(rows, indices, filters, colMap, locale) {
|
|
|
367
496
|
/**
|
|
368
497
|
* Evaluate a text, number, or date condition for one cell value.
|
|
369
498
|
*/
|
|
370
|
-
function passesConditionFilter(col, raw, filter, locale) {
|
|
499
|
+
function passesConditionFilter(col, raw, filter, locale, row) {
|
|
371
500
|
if (col?.type !== 'number' && col?.type !== 'date') {
|
|
372
|
-
const value = getDisplayForField(col, raw, locale).toLocaleLowerCase(locale);
|
|
501
|
+
const value = getDisplayForField(col, raw, locale, row).toLocaleLowerCase(locale);
|
|
373
502
|
const operand = String(filter.operand ?? '').toLocaleLowerCase(locale);
|
|
374
503
|
switch (filter.operator) {
|
|
375
504
|
case 'eq': return value === operand;
|
|
@@ -420,7 +549,7 @@ function applyQuickFilter(rows, indices, text, cols, locale) {
|
|
|
420
549
|
const q = text.trim().toLowerCase();
|
|
421
550
|
if (!q)
|
|
422
551
|
return indices;
|
|
423
|
-
return indices.filter(i => cols.some(col => getDisplayForField(col, rows[i][col.field], locale).toLowerCase().includes(q)));
|
|
552
|
+
return indices.filter(i => cols.some(col => getDisplayForField(col, rows[i][col.field], locale, rows[i]).toLowerCase().includes(q)));
|
|
424
553
|
}
|
|
425
554
|
// Sorting
|
|
426
555
|
/**
|
|
@@ -456,7 +585,7 @@ function applySortToIndices(rows, indices, sortEntries, colMap, locale) {
|
|
|
456
585
|
dateLike[position] = isDateLike ? 1 : 0;
|
|
457
586
|
dateValues[position] = Number.isNaN(dateValue) ? -1 : dateValue;
|
|
458
587
|
numericValues[position] = numericValue;
|
|
459
|
-
displayValues[position] = isDateLike ? '' : getDisplayForField(col, raw, locale);
|
|
588
|
+
displayValues[position] = isDateLike ? '' : getDisplayForField(col, raw, locale, rows[index]);
|
|
460
589
|
}
|
|
461
590
|
return {
|
|
462
591
|
direction: filter.sort === 'desc' ? -1 : 1,
|
|
@@ -911,6 +1040,8 @@ function resolveCellSpanAnchor(columns, columnIndex, row, originalIndex) {
|
|
|
911
1040
|
return { anchorIndex: columnIndex, span: 1 };
|
|
912
1041
|
}
|
|
913
1042
|
|
|
1043
|
+
const DEFAULT_CELL_SPAN_LAYOUT = { covered: false, span: 1 };
|
|
1044
|
+
const EMPTY_CELL_FORMAT = {};
|
|
914
1045
|
/**
|
|
915
1046
|
* Individual cell component used inside `AgridComponent`.
|
|
916
1047
|
*
|
|
@@ -925,6 +1056,8 @@ class AgridCellComponent {
|
|
|
925
1056
|
col = input.required(...(ngDevMode ? [{ debugName: "col" }] : /* istanbul ignore next */ []));
|
|
926
1057
|
/** Visible columns in this cell's pane, used to clamp spans at pane boundaries. */
|
|
927
1058
|
paneColumns = input([], ...(ngDevMode ? [{ debugName: "paneColumns" }] : /* istanbul ignore next */ []));
|
|
1059
|
+
/** Whether any visible column in this pane can span cells. */
|
|
1060
|
+
paneHasSpans = input(false, ...(ngDevMode ? [{ debugName: "paneHasSpans" }] : /* istanbul ignore next */ []));
|
|
928
1061
|
/** Absolute row index within the data source. */
|
|
929
1062
|
rowIndex = input.required(...(ngDevMode ? [{ debugName: "rowIndex" }] : /* istanbul ignore next */ []));
|
|
930
1063
|
/** Column index within `colDefs`. */
|
|
@@ -936,16 +1069,23 @@ class AgridCellComponent {
|
|
|
936
1069
|
/** Full row data — passed to `cellRenderer` when set. */
|
|
937
1070
|
row = input({}, ...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
938
1071
|
/** Horizontal span and coverage state for this row. */
|
|
939
|
-
cellSpanLayout = computed(() =>
|
|
1072
|
+
cellSpanLayout = computed(() => {
|
|
1073
|
+
if (!this.paneHasSpans())
|
|
1074
|
+
return DEFAULT_CELL_SPAN_LAYOUT;
|
|
1075
|
+
const paneColumns = this.paneColumns();
|
|
1076
|
+
return resolveCellSpanLayout(paneColumns, paneColumns.indexOf(this.col()), this.row(), this.rowIndex());
|
|
1077
|
+
}, ...(ngDevMode ? [{ debugName: "cellSpanLayout" }] : /* istanbul ignore next */ []));
|
|
940
1078
|
/** Runtime formatting resolved from the column definition and current cell context. */
|
|
941
1079
|
resolvedCellFormat = computed(() => {
|
|
942
1080
|
const col = this.col();
|
|
1081
|
+
if (!col.cellFormat)
|
|
1082
|
+
return EMPTY_CELL_FORMAT;
|
|
943
1083
|
return col.cellFormat?.({
|
|
944
1084
|
row: this.row(),
|
|
945
1085
|
value: this.value(),
|
|
946
1086
|
column: col,
|
|
947
1087
|
originalIndex: this.rowIndex(),
|
|
948
|
-
}) ??
|
|
1088
|
+
}) ?? EMPTY_CELL_FORMAT;
|
|
949
1089
|
}, ...(ngDevMode ? [{ debugName: "resolvedCellFormat" }] : /* istanbul ignore next */ []));
|
|
950
1090
|
/** Per-cell formatting wins over the column's default text alignment. */
|
|
951
1091
|
resolvedTextAlign = computed(() => {
|
|
@@ -1006,6 +1146,10 @@ class AgridCellComponent {
|
|
|
1006
1146
|
editorCancel = output();
|
|
1007
1147
|
/** Live draft value managed by the cell during an active edit. */
|
|
1008
1148
|
draft = signal('', ...(ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []));
|
|
1149
|
+
asyncValueOptions = signal([], ...(ngDevMode ? [{ debugName: "asyncValueOptions" }] : /* istanbul ignore next */ []));
|
|
1150
|
+
asyncValueLoading = signal(false, ...(ngDevMode ? [{ debugName: "asyncValueLoading" }] : /* istanbul ignore next */ []));
|
|
1151
|
+
richSelectSearch = signal('', ...(ngDevMode ? [{ debugName: "richSelectSearch" }] : /* istanbul ignore next */ []));
|
|
1152
|
+
asyncValueLoadId = 0;
|
|
1009
1153
|
/**
|
|
1010
1154
|
* Context exposed to a {@link ColDef.cellEditor} component via {@link AGRID_EDITOR_CONTEXT}.
|
|
1011
1155
|
* The signals are the cell's own inputs, so the editor stays reactive to value/row changes.
|
|
@@ -1082,17 +1226,24 @@ class AgridCellComponent {
|
|
|
1082
1226
|
*/
|
|
1083
1227
|
valueOptions = computed(() => {
|
|
1084
1228
|
const vals = this.col().values ?? [];
|
|
1085
|
-
|
|
1229
|
+
const sync = vals.map(v => typeof v === 'string'
|
|
1086
1230
|
? { label: v, rawValue: v }
|
|
1087
1231
|
: { label: v.label, rawValue: v.value });
|
|
1232
|
+
return sync.length ? sync : this.asyncValueOptions();
|
|
1088
1233
|
}, ...(ngDevMode ? [{ debugName: "valueOptions" }] : /* istanbul ignore next */ []));
|
|
1234
|
+
filteredValueOptions = computed(() => {
|
|
1235
|
+
const search = this.richSelectSearch().toLowerCase();
|
|
1236
|
+
return this.valueOptions()
|
|
1237
|
+
.filter(item => !search || item.label.toLowerCase().includes(search))
|
|
1238
|
+
.slice(0, Math.max(1, Math.floor(this.col().filterValueLimit ?? 100)));
|
|
1239
|
+
}, ...(ngDevMode ? [{ debugName: "filteredValueOptions" }] : /* istanbul ignore next */ []));
|
|
1089
1240
|
/**
|
|
1090
1241
|
* The string shown in the cell when not editing.
|
|
1091
1242
|
* Priority: ValueOption label → `ColDef.formatter` → raw string.
|
|
1092
1243
|
*/
|
|
1093
1244
|
displayValue = computed(() => {
|
|
1094
1245
|
return this.displayValueOverride()
|
|
1095
|
-
?? getDisplayForField(this.col(), this.value(), this.locale());
|
|
1246
|
+
?? getDisplayForField(this.col(), this.value(), this.locale(), this.row());
|
|
1096
1247
|
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
1097
1248
|
/**
|
|
1098
1249
|
* Index of the currently selected option in `valueOptions`.
|
|
@@ -1105,9 +1256,16 @@ class AgridCellComponent {
|
|
|
1105
1256
|
}, ...(ngDevMode ? [{ debugName: "selectedOptionIndex" }] : /* istanbul ignore next */ []));
|
|
1106
1257
|
inputEl = viewChild('editInput', ...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
|
|
1107
1258
|
selectEl = viewChild('editSelect', ...(ngDevMode ? [{ debugName: "selectEl" }] : /* istanbul ignore next */ []));
|
|
1259
|
+
largeTextEl = viewChild('largeTextInput', ...(ngDevMode ? [{ debugName: "largeTextEl" }] : /* istanbul ignore next */ []));
|
|
1260
|
+
richSelectEl = viewChild('richSelectInput', ...(ngDevMode ? [{ debugName: "richSelectEl" }] : /* istanbul ignore next */ []));
|
|
1261
|
+
richSelectEditor = computed(() => this.col().editor === 'richSelect'
|
|
1262
|
+
|| (!!this.col().asyncValues && this.editing()), ...(ngDevMode ? [{ debugName: "richSelectEditor" }] : /* istanbul ignore next */ []));
|
|
1263
|
+
largeTextEditor = computed(() => this.col().editor === 'largeText', ...(ngDevMode ? [{ debugName: "largeTextEditor" }] : /* istanbul ignore next */ []));
|
|
1264
|
+
formulaEditor = computed(() => this.col().editor === 'formula' || !!this.col().formula, ...(ngDevMode ? [{ debugName: "formulaEditor" }] : /* istanbul ignore next */ []));
|
|
1108
1265
|
constructor() {
|
|
1109
1266
|
effect(() => {
|
|
1110
1267
|
if (this.editing()) {
|
|
1268
|
+
this.loadAsyncValues();
|
|
1111
1269
|
const seed = this.seedChar();
|
|
1112
1270
|
const isDate = this.col().type === 'date';
|
|
1113
1271
|
const existingDate = isDate ? getDateInputValue(this.value()) : '';
|
|
@@ -1136,6 +1294,23 @@ class AgridCellComponent {
|
|
|
1136
1294
|
}
|
|
1137
1295
|
return;
|
|
1138
1296
|
}
|
|
1297
|
+
const largeText = this.largeTextEl()?.nativeElement;
|
|
1298
|
+
if (largeText) {
|
|
1299
|
+
largeText.value = String(acceptedInitialValue ?? '');
|
|
1300
|
+
largeText.focus();
|
|
1301
|
+
if (!seed && this.selectTextOnEdit())
|
|
1302
|
+
largeText.select();
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
const richSelect = this.richSelectEl()?.nativeElement;
|
|
1306
|
+
if (richSelect) {
|
|
1307
|
+
const current = this.valueOptions().find(option => option.rawValue === acceptedInitialValue);
|
|
1308
|
+
this.richSelectSearch.set(seed || current?.label || String(acceptedInitialValue ?? ''));
|
|
1309
|
+
richSelect.focus();
|
|
1310
|
+
if (!seed)
|
|
1311
|
+
richSelect.select();
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1139
1314
|
const sel = this.selectEl()?.nativeElement;
|
|
1140
1315
|
if (sel) {
|
|
1141
1316
|
const idx = this.selectedOptionIndex();
|
|
@@ -1199,8 +1374,43 @@ class AgridCellComponent {
|
|
|
1199
1374
|
this.draft.set(rawValue);
|
|
1200
1375
|
this.draftChange.emit(rawValue);
|
|
1201
1376
|
}
|
|
1377
|
+
onRichSelectSearch(event) {
|
|
1378
|
+
this.richSelectSearch.set(event.target.value);
|
|
1379
|
+
}
|
|
1380
|
+
pickRichSelectOption(rawValue) {
|
|
1381
|
+
this.draft.set(rawValue);
|
|
1382
|
+
this.draftChange.emit(rawValue);
|
|
1383
|
+
const selected = this.valueOptions().find(option => option.rawValue === rawValue);
|
|
1384
|
+
this.richSelectSearch.set(selected?.label ?? String(rawValue ?? ''));
|
|
1385
|
+
this.editorCommit.emit();
|
|
1386
|
+
}
|
|
1387
|
+
loadAsyncValues() {
|
|
1388
|
+
const provider = this.col().asyncValues;
|
|
1389
|
+
if (!provider || this.col().values?.length)
|
|
1390
|
+
return;
|
|
1391
|
+
const loadId = ++this.asyncValueLoadId;
|
|
1392
|
+
this.asyncValueLoading.set(true);
|
|
1393
|
+
Promise.resolve(provider({
|
|
1394
|
+
row: this.row(),
|
|
1395
|
+
value: this.value(),
|
|
1396
|
+
column: this.col(),
|
|
1397
|
+
originalIndex: this.rowIndex(),
|
|
1398
|
+
})).then(values => {
|
|
1399
|
+
if (loadId !== this.asyncValueLoadId)
|
|
1400
|
+
return;
|
|
1401
|
+
this.asyncValueOptions.set(values.map(value => typeof value === 'string'
|
|
1402
|
+
? { label: value, rawValue: value }
|
|
1403
|
+
: { label: value.label, rawValue: value.value }));
|
|
1404
|
+
}).catch(() => {
|
|
1405
|
+
if (loadId === this.asyncValueLoadId)
|
|
1406
|
+
this.asyncValueOptions.set([]);
|
|
1407
|
+
}).finally(() => {
|
|
1408
|
+
if (loadId === this.asyncValueLoadId)
|
|
1409
|
+
this.asyncValueLoading.set(false);
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1202
1412
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1203
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridCellComponent, isStandalone: true, selector: "agrid-cell", inputs: { localeText: { classPropertyName: "localeText", publicName: "localeText", isSignal: true, isRequired: false, transformFunction: null }, col: { classPropertyName: "col", publicName: "col", isSignal: true, isRequired: true, transformFunction: null }, paneColumns: { classPropertyName: "paneColumns", publicName: "paneColumns", isSignal: true, isRequired: false, transformFunction: null }, rowIndex: { classPropertyName: "rowIndex", publicName: "rowIndex", isSignal: true, isRequired: true, transformFunction: null }, colIndex: { classPropertyName: "colIndex", publicName: "colIndex", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, displayValueOverride: { classPropertyName: "displayValueOverride", publicName: "displayValueOverride", isSignal: true, isRequired: false, transformFunction: null }, row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, editing: { classPropertyName: "editing", publicName: "editing", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, showInfoIcon: { classPropertyName: "showInfoIcon", publicName: "showInfoIcon", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, treeCell: { classPropertyName: "treeCell", publicName: "treeCell", isSignal: true, isRequired: false, transformFunction: null }, treeLevel: { classPropertyName: "treeLevel", publicName: "treeLevel", isSignal: true, isRequired: false, transformFunction: null }, treeExpandable: { classPropertyName: "treeExpandable", publicName: "treeExpandable", isSignal: true, isRequired: false, transformFunction: null }, treeExpanded: { classPropertyName: "treeExpanded", publicName: "treeExpanded", isSignal: true, isRequired: false, transformFunction: null }, seedChar: { classPropertyName: "seedChar", publicName: "seedChar", isSignal: true, isRequired: false, transformFunction: null }, selectTextOnEdit: { classPropertyName: "selectTextOnEdit", publicName: "selectTextOnEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { treeToggle: "treeToggle", activate: "activate", startEdit: "startEdit", booleanToggle: "booleanToggle", infoClick: "infoClick", draftChange: "draftChange", editorCommit: "editorCommit", editorCancel: "editorCancel" }, host: { attributes: { "role": "gridcell", "tabindex": "-1" }, listeners: { "click": "activate.emit($event)", "dblclick": "startEdit.emit()" }, properties: { "class.selected": "selected()", "class.editing": "editing()", "class.ag-cell--tree": "treeCell()", "class.ag-cell--with-info": "showInfoIcon() && !editing()", "attr.aria-readonly": "!editable() ? \"true\" : null", "attr.aria-colspan": "cellSpanLayout().span > 1 ? cellSpanLayout().span : null", "style.display": "cellSpanLayout().covered ? \"none\" : null", "style.grid-column": "cellSpanLayout().span > 1 ? \"span \" + cellSpanLayout().span : null", "attr.title": "displayValue()", "style.background-color": "resolvedCellFormat().backgroundColor ?? null", "style.border-color": "resolvedCellFormat().borderColor ?? null", "style.color": "resolvedCellFormat().color ?? null", "style.font": "resolvedCellFormat().font ?? null", "style.font-family": "resolvedCellFormat().fontFamily ?? null", "style.font-size": "resolvedCellFormat().fontSize ?? null", "style.font-style": "resolvedCellFormat().fontStyle ?? null", "style.font-weight": "resolvedCellFormat().fontWeight ?? null", "style.text-decoration": "resolvedCellFormat().textDecoration ?? null", "style.text-align": "resolvedTextAlign()" } }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["editInput"], descendants: true, isSignal: true }, { propertyName: "selectEl", first: true, predicate: ["editSelect"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1413
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridCellComponent, isStandalone: true, selector: "agrid-cell", inputs: { localeText: { classPropertyName: "localeText", publicName: "localeText", isSignal: true, isRequired: false, transformFunction: null }, col: { classPropertyName: "col", publicName: "col", isSignal: true, isRequired: true, transformFunction: null }, paneColumns: { classPropertyName: "paneColumns", publicName: "paneColumns", isSignal: true, isRequired: false, transformFunction: null }, paneHasSpans: { classPropertyName: "paneHasSpans", publicName: "paneHasSpans", isSignal: true, isRequired: false, transformFunction: null }, rowIndex: { classPropertyName: "rowIndex", publicName: "rowIndex", isSignal: true, isRequired: true, transformFunction: null }, colIndex: { classPropertyName: "colIndex", publicName: "colIndex", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, displayValueOverride: { classPropertyName: "displayValueOverride", publicName: "displayValueOverride", isSignal: true, isRequired: false, transformFunction: null }, row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, editing: { classPropertyName: "editing", publicName: "editing", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, showInfoIcon: { classPropertyName: "showInfoIcon", publicName: "showInfoIcon", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, treeCell: { classPropertyName: "treeCell", publicName: "treeCell", isSignal: true, isRequired: false, transformFunction: null }, treeLevel: { classPropertyName: "treeLevel", publicName: "treeLevel", isSignal: true, isRequired: false, transformFunction: null }, treeExpandable: { classPropertyName: "treeExpandable", publicName: "treeExpandable", isSignal: true, isRequired: false, transformFunction: null }, treeExpanded: { classPropertyName: "treeExpanded", publicName: "treeExpanded", isSignal: true, isRequired: false, transformFunction: null }, seedChar: { classPropertyName: "seedChar", publicName: "seedChar", isSignal: true, isRequired: false, transformFunction: null }, selectTextOnEdit: { classPropertyName: "selectTextOnEdit", publicName: "selectTextOnEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { treeToggle: "treeToggle", activate: "activate", startEdit: "startEdit", booleanToggle: "booleanToggle", infoClick: "infoClick", draftChange: "draftChange", editorCommit: "editorCommit", editorCancel: "editorCancel" }, host: { attributes: { "role": "gridcell", "tabindex": "-1" }, listeners: { "click": "activate.emit($event)", "dblclick": "startEdit.emit()" }, properties: { "class.selected": "selected()", "class.editing": "editing()", "class.ag-cell--tree": "treeCell()", "class.ag-cell--with-info": "showInfoIcon() && !editing()", "attr.aria-readonly": "!editable() ? \"true\" : null", "attr.aria-colspan": "cellSpanLayout().span > 1 ? cellSpanLayout().span : null", "style.display": "cellSpanLayout().covered ? \"none\" : null", "style.grid-column": "cellSpanLayout().span > 1 ? \"span \" + cellSpanLayout().span : null", "attr.title": "displayValue()", "style.background-color": "resolvedCellFormat().backgroundColor ?? null", "style.border-color": "resolvedCellFormat().borderColor ?? null", "style.color": "resolvedCellFormat().color ?? null", "style.font": "resolvedCellFormat().font ?? null", "style.font-family": "resolvedCellFormat().fontFamily ?? null", "style.font-size": "resolvedCellFormat().fontSize ?? null", "style.font-style": "resolvedCellFormat().fontStyle ?? null", "style.font-weight": "resolvedCellFormat().fontWeight ?? null", "style.text-decoration": "resolvedCellFormat().textDecoration ?? null", "style.text-align": "resolvedTextAlign()" } }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["editInput"], descendants: true, isSignal: true }, { propertyName: "selectEl", first: true, predicate: ["editSelect"], descendants: true, isSignal: true }, { propertyName: "largeTextEl", first: true, predicate: ["largeTextInput"], descendants: true, isSignal: true }, { propertyName: "richSelectEl", first: true, predicate: ["richSelectInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1204
1414
|
@if (booleanCell()) {
|
|
1205
1415
|
<input
|
|
1206
1416
|
type="checkbox"
|
|
@@ -1221,6 +1431,40 @@ class AgridCellComponent {
|
|
|
1221
1431
|
>
|
|
1222
1432
|
<ng-container [ngComponentOutlet]="editor" [ngComponentOutletInjector]="editorInjector" />
|
|
1223
1433
|
</div>
|
|
1434
|
+
} @else if (richSelectEditor()) {
|
|
1435
|
+
<div class="ag-rich-select-editor" (keydown)="$event.stopPropagation()">
|
|
1436
|
+
<input
|
|
1437
|
+
#richSelectInput
|
|
1438
|
+
class="ag-cell-input ag-rich-select-input"
|
|
1439
|
+
[value]="richSelectSearch()"
|
|
1440
|
+
(input)="onRichSelectSearch($event)"
|
|
1441
|
+
[attr.placeholder]="asyncValueLoading() ? 'Loading...' : ''"
|
|
1442
|
+
/>
|
|
1443
|
+
<div class="ag-rich-select-panel" role="listbox">
|
|
1444
|
+
@if (asyncValueLoading()) {
|
|
1445
|
+
<div class="ag-rich-select-empty">Loading...</div>
|
|
1446
|
+
} @else {
|
|
1447
|
+
@for (opt of filteredValueOptions(); track opt.label; let idx = $index) {
|
|
1448
|
+
<button
|
|
1449
|
+
type="button"
|
|
1450
|
+
class="ag-rich-select-option"
|
|
1451
|
+
[class.ag-rich-select-option--active]="opt.rawValue === draft()"
|
|
1452
|
+
(click)="pickRichSelectOption(opt.rawValue)"
|
|
1453
|
+
>{{ opt.label }}</button>
|
|
1454
|
+
} @empty {
|
|
1455
|
+
<div class="ag-rich-select-empty">No matches</div>
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
</div>
|
|
1459
|
+
</div>
|
|
1460
|
+
} @else if (largeTextEditor()) {
|
|
1461
|
+
<textarea
|
|
1462
|
+
#largeTextInput
|
|
1463
|
+
class="ag-cell-large-text"
|
|
1464
|
+
[class.ag-cell-input--invalid]="!!error()"
|
|
1465
|
+
[value]="editorValue()"
|
|
1466
|
+
(input)="onInput($event)"
|
|
1467
|
+
></textarea>
|
|
1224
1468
|
} @else if (col().values?.length) {
|
|
1225
1469
|
<select
|
|
1226
1470
|
#editSelect
|
|
@@ -1235,6 +1479,7 @@ class AgridCellComponent {
|
|
|
1235
1479
|
<input
|
|
1236
1480
|
#editInput
|
|
1237
1481
|
class="ag-cell-input"
|
|
1482
|
+
[class.ag-cell-input--formula]="formulaEditor()"
|
|
1238
1483
|
[class.ag-cell-input--invalid]="!!error()"
|
|
1239
1484
|
[type]="col().type === 'date' ? 'date' : 'text'"
|
|
1240
1485
|
[attr.inputmode]="col().type === 'number' ? 'decimal' : null"
|
|
@@ -1280,7 +1525,7 @@ class AgridCellComponent {
|
|
|
1280
1525
|
(dblclick)="$event.stopPropagation()"
|
|
1281
1526
|
>?</button>
|
|
1282
1527
|
}
|
|
1283
|
-
`, isInline: true, styles: [":host{position:relative;display:block;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;padding:0 6px;line-height:32px;cursor:default;-webkit-user-select:none;user-select:none;outline:none;box-sizing:border-box}:host(.ag-cell--changed):after{content:\"\";position:absolute;top:0;right:0;width:0;height:0;border-top:8px solid var(--agrid-color-cell-changed);border-left:8px solid transparent;pointer-events:none}:host(.selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.ag-cell--range-selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.editing){padding:0;background:var(--agrid-color-bg)}.ag-cell-value{display:block;overflow:hidden;text-overflow:ellipsis}.ag-cell-editor{display:flex;align-items:center;width:100%;height:100%;min-width:0}:host(.ag-cell--tree){display:flex;align-items:center}:host(.ag-cell--tree) .ag-cell-value{flex:1 1 auto;min-width:0}:host(.ag-cell--with-info) .ag-cell-value{padding-right:22px}.ag-cell-info{position:absolute;top:50%;right:4px;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:1px solid var(--agrid-color-border);border-radius:50%;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);font:600 11px/1 sans-serif;cursor:pointer}.ag-cell-info:hover,.ag-cell-info:focus-visible{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent);outline:none}.ag-tree-prefix{flex:0 0 auto;display:inline-flex;align-items:center;height:100%}.ag-tree-twisty,.ag-tree-twisty-spacer{width:16px;flex:0 0 16px}.ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;height:100%;padding:0;border:none;background:transparent;color:var(--agrid-color-text-muted);font-size:9px;line-height:1;cursor:pointer;transition:transform .15s ease}.ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-cell-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent;user-select:text;-webkit-user-select:text}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}.ag-cell-checkbox{display:block;margin:9px auto;cursor:pointer;accent-color:var(--agrid-color-accent)}.ag-cell-checkbox:disabled{cursor:not-allowed;opacity:.6}.ag-cell-input--invalid{outline:2px solid var(--agrid-color-danger);outline-offset:-2px}.ag-cell-error{position:absolute;left:0;top:100%;z-index:5;max-width:240px;padding:3px 8px;font-size:12px;line-height:1.4;white-space:normal;color:#fff;background:var(--agrid-color-danger);border-radius:0 0 4px 4px;box-shadow:0 2px 6px #0000002e;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1528
|
+
`, isInline: true, styles: [":host{position:relative;display:block;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;padding:0 6px;line-height:32px;cursor:default;-webkit-user-select:none;user-select:none;outline:none;box-sizing:border-box}:host(.ag-cell--changed):after{content:\"\";position:absolute;top:0;right:0;width:0;height:0;border-top:8px solid var(--agrid-color-cell-changed);border-left:8px solid transparent;pointer-events:none}:host(.selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.ag-cell--range-selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.editing){padding:0;background:var(--agrid-color-bg);overflow:visible;z-index:6}.ag-cell-value{display:block;overflow:hidden;text-overflow:ellipsis}.ag-cell-editor{display:flex;align-items:center;width:100%;height:100%;min-width:0}:host(.ag-cell--tree){display:flex;align-items:center}:host(.ag-cell--tree) .ag-cell-value{flex:1 1 auto;min-width:0}:host(.ag-cell--with-info) .ag-cell-value{padding-right:22px}.ag-cell-info{position:absolute;top:50%;right:4px;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:1px solid var(--agrid-color-border);border-radius:50%;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);font:600 11px/1 sans-serif;cursor:pointer}.ag-cell-info:hover,.ag-cell-info:focus-visible{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent);outline:none}.ag-tree-prefix{flex:0 0 auto;display:inline-flex;align-items:center;height:100%}.ag-tree-twisty,.ag-tree-twisty-spacer{width:16px;flex:0 0 16px}.ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;height:100%;padding:0;border:none;background:transparent;color:var(--agrid-color-text-muted);font-size:9px;line-height:1;cursor:pointer;transition:transform .15s ease}.ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-cell-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent;user-select:text;-webkit-user-select:text}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}.ag-cell-large-text{position:absolute;z-index:8;top:0;left:0;width:min(360px,max(100%,280px));min-height:116px;border:1px solid var(--agrid-color-accent);outline:none;resize:both;font:inherit;line-height:1.4;padding:6px 8px;box-sizing:border-box;color:var(--agrid-color-text);background:var(--agrid-color-bg);box-shadow:0 8px 24px var(--agrid-color-shadow);user-select:text;-webkit-user-select:text}.ag-cell-input--formula{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;color:var(--agrid-color-accent-fg);background:var(--agrid-color-accent-subtle)}.ag-rich-select-editor{position:absolute;z-index:8;top:0;left:0;width:min(320px,max(100%,240px));color:var(--agrid-color-text);background:var(--agrid-color-bg);border:1px solid var(--agrid-color-accent);box-shadow:0 8px 24px var(--agrid-color-shadow)}.ag-rich-select-input{height:32px;border-bottom:1px solid var(--agrid-color-border)}.ag-rich-select-panel{max-height:180px;overflow:auto;padding:3px;background:var(--agrid-color-bg)}.ag-rich-select-option{display:block;width:100%;min-height:26px;border:0;border-radius:3px;background:transparent;color:var(--agrid-color-text);font:inherit;line-height:1.2;text-align:left;padding:4px 7px;cursor:pointer}.ag-rich-select-option:hover,.ag-rich-select-option--active{background:var(--agrid-color-accent-subtle);color:var(--agrid-color-accent-fg)}.ag-rich-select-empty{padding:7px;color:var(--agrid-color-text-muted);font-size:12px;line-height:1.3}.ag-cell-checkbox{display:block;margin:9px auto;cursor:pointer;accent-color:var(--agrid-color-accent)}.ag-cell-checkbox:disabled{cursor:not-allowed;opacity:.6}.ag-cell-input--invalid{outline:2px solid var(--agrid-color-danger);outline-offset:-2px}.ag-cell-error{position:absolute;left:0;top:100%;z-index:5;max-width:240px;padding:3px 8px;font-size:12px;line-height:1.4;white-space:normal;color:#fff;background:var(--agrid-color-danger);border-radius:0 0 4px 4px;box-shadow:0 2px 6px #0000002e;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1284
1529
|
}
|
|
1285
1530
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridCellComponent, decorators: [{
|
|
1286
1531
|
type: Component,
|
|
@@ -1329,6 +1574,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
1329
1574
|
>
|
|
1330
1575
|
<ng-container [ngComponentOutlet]="editor" [ngComponentOutletInjector]="editorInjector" />
|
|
1331
1576
|
</div>
|
|
1577
|
+
} @else if (richSelectEditor()) {
|
|
1578
|
+
<div class="ag-rich-select-editor" (keydown)="$event.stopPropagation()">
|
|
1579
|
+
<input
|
|
1580
|
+
#richSelectInput
|
|
1581
|
+
class="ag-cell-input ag-rich-select-input"
|
|
1582
|
+
[value]="richSelectSearch()"
|
|
1583
|
+
(input)="onRichSelectSearch($event)"
|
|
1584
|
+
[attr.placeholder]="asyncValueLoading() ? 'Loading...' : ''"
|
|
1585
|
+
/>
|
|
1586
|
+
<div class="ag-rich-select-panel" role="listbox">
|
|
1587
|
+
@if (asyncValueLoading()) {
|
|
1588
|
+
<div class="ag-rich-select-empty">Loading...</div>
|
|
1589
|
+
} @else {
|
|
1590
|
+
@for (opt of filteredValueOptions(); track opt.label; let idx = $index) {
|
|
1591
|
+
<button
|
|
1592
|
+
type="button"
|
|
1593
|
+
class="ag-rich-select-option"
|
|
1594
|
+
[class.ag-rich-select-option--active]="opt.rawValue === draft()"
|
|
1595
|
+
(click)="pickRichSelectOption(opt.rawValue)"
|
|
1596
|
+
>{{ opt.label }}</button>
|
|
1597
|
+
} @empty {
|
|
1598
|
+
<div class="ag-rich-select-empty">No matches</div>
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
</div>
|
|
1602
|
+
</div>
|
|
1603
|
+
} @else if (largeTextEditor()) {
|
|
1604
|
+
<textarea
|
|
1605
|
+
#largeTextInput
|
|
1606
|
+
class="ag-cell-large-text"
|
|
1607
|
+
[class.ag-cell-input--invalid]="!!error()"
|
|
1608
|
+
[value]="editorValue()"
|
|
1609
|
+
(input)="onInput($event)"
|
|
1610
|
+
></textarea>
|
|
1332
1611
|
} @else if (col().values?.length) {
|
|
1333
1612
|
<select
|
|
1334
1613
|
#editSelect
|
|
@@ -1343,6 +1622,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
1343
1622
|
<input
|
|
1344
1623
|
#editInput
|
|
1345
1624
|
class="ag-cell-input"
|
|
1625
|
+
[class.ag-cell-input--formula]="formulaEditor()"
|
|
1346
1626
|
[class.ag-cell-input--invalid]="!!error()"
|
|
1347
1627
|
[type]="col().type === 'date' ? 'date' : 'text'"
|
|
1348
1628
|
[attr.inputmode]="col().type === 'number' ? 'decimal' : null"
|
|
@@ -1388,8 +1668,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
1388
1668
|
(dblclick)="$event.stopPropagation()"
|
|
1389
1669
|
>?</button>
|
|
1390
1670
|
}
|
|
1391
|
-
`, styles: [":host{position:relative;display:block;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;padding:0 6px;line-height:32px;cursor:default;-webkit-user-select:none;user-select:none;outline:none;box-sizing:border-box}:host(.ag-cell--changed):after{content:\"\";position:absolute;top:0;right:0;width:0;height:0;border-top:8px solid var(--agrid-color-cell-changed);border-left:8px solid transparent;pointer-events:none}:host(.selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.ag-cell--range-selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.editing){padding:0;background:var(--agrid-color-bg)}.ag-cell-value{display:block;overflow:hidden;text-overflow:ellipsis}.ag-cell-editor{display:flex;align-items:center;width:100%;height:100%;min-width:0}:host(.ag-cell--tree){display:flex;align-items:center}:host(.ag-cell--tree) .ag-cell-value{flex:1 1 auto;min-width:0}:host(.ag-cell--with-info) .ag-cell-value{padding-right:22px}.ag-cell-info{position:absolute;top:50%;right:4px;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:1px solid var(--agrid-color-border);border-radius:50%;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);font:600 11px/1 sans-serif;cursor:pointer}.ag-cell-info:hover,.ag-cell-info:focus-visible{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent);outline:none}.ag-tree-prefix{flex:0 0 auto;display:inline-flex;align-items:center;height:100%}.ag-tree-twisty,.ag-tree-twisty-spacer{width:16px;flex:0 0 16px}.ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;height:100%;padding:0;border:none;background:transparent;color:var(--agrid-color-text-muted);font-size:9px;line-height:1;cursor:pointer;transition:transform .15s ease}.ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-cell-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent;user-select:text;-webkit-user-select:text}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}.ag-cell-checkbox{display:block;margin:9px auto;cursor:pointer;accent-color:var(--agrid-color-accent)}.ag-cell-checkbox:disabled{cursor:not-allowed;opacity:.6}.ag-cell-input--invalid{outline:2px solid var(--agrid-color-danger);outline-offset:-2px}.ag-cell-error{position:absolute;left:0;top:100%;z-index:5;max-width:240px;padding:3px 8px;font-size:12px;line-height:1.4;white-space:normal;color:#fff;background:var(--agrid-color-danger);border-radius:0 0 4px 4px;box-shadow:0 2px 6px #0000002e;pointer-events:none}\n"] }]
|
|
1392
|
-
}], ctorParameters: () => [], propDecorators: { localeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "localeText", required: false }] }], col: [{ type: i0.Input, args: [{ isSignal: true, alias: "col", required: true }] }], paneColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "paneColumns", required: false }] }], rowIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowIndex", required: true }] }], colIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "colIndex", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], displayValueOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayValueOverride", required: false }] }], row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], editing: [{ type: i0.Input, args: [{ isSignal: true, alias: "editing", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], showInfoIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showInfoIcon", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], treeCell: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeCell", required: false }] }], treeLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeLevel", required: false }] }], treeExpandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeExpandable", required: false }] }], treeExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeExpanded", required: false }] }], treeToggle: [{ type: i0.Output, args: ["treeToggle"] }], seedChar: [{ type: i0.Input, args: [{ isSignal: true, alias: "seedChar", required: false }] }], selectTextOnEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectTextOnEdit", required: false }] }], activate: [{ type: i0.Output, args: ["activate"] }], startEdit: [{ type: i0.Output, args: ["startEdit"] }], booleanToggle: [{ type: i0.Output, args: ["booleanToggle"] }], infoClick: [{ type: i0.Output, args: ["infoClick"] }], draftChange: [{ type: i0.Output, args: ["draftChange"] }], editorCommit: [{ type: i0.Output, args: ["editorCommit"] }], editorCancel: [{ type: i0.Output, args: ["editorCancel"] }], inputEl: [{ type: i0.ViewChild, args: ['editInput', { isSignal: true }] }], selectEl: [{ type: i0.ViewChild, args: ['editSelect', { isSignal: true }] }] } });
|
|
1671
|
+
`, styles: [":host{position:relative;display:block;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;padding:0 6px;line-height:32px;cursor:default;-webkit-user-select:none;user-select:none;outline:none;box-sizing:border-box}:host(.ag-cell--changed):after{content:\"\";position:absolute;top:0;right:0;width:0;height:0;border-top:8px solid var(--agrid-color-cell-changed);border-left:8px solid transparent;pointer-events:none}:host(.selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.ag-cell--range-selected){outline:2px solid var(--agrid-color-accent);outline-offset:-2px}:host(.editing){padding:0;background:var(--agrid-color-bg);overflow:visible;z-index:6}.ag-cell-value{display:block;overflow:hidden;text-overflow:ellipsis}.ag-cell-editor{display:flex;align-items:center;width:100%;height:100%;min-width:0}:host(.ag-cell--tree){display:flex;align-items:center}:host(.ag-cell--tree) .ag-cell-value{flex:1 1 auto;min-width:0}:host(.ag-cell--with-info) .ag-cell-value{padding-right:22px}.ag-cell-info{position:absolute;top:50%;right:4px;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:1px solid var(--agrid-color-border);border-radius:50%;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);font:600 11px/1 sans-serif;cursor:pointer}.ag-cell-info:hover,.ag-cell-info:focus-visible{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent);outline:none}.ag-tree-prefix{flex:0 0 auto;display:inline-flex;align-items:center;height:100%}.ag-tree-twisty,.ag-tree-twisty-spacer{width:16px;flex:0 0 16px}.ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;height:100%;padding:0;border:none;background:transparent;color:var(--agrid-color-text-muted);font-size:9px;line-height:1;cursor:pointer;transition:transform .15s ease}.ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-cell-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent;user-select:text;-webkit-user-select:text}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}.ag-cell-large-text{position:absolute;z-index:8;top:0;left:0;width:min(360px,max(100%,280px));min-height:116px;border:1px solid var(--agrid-color-accent);outline:none;resize:both;font:inherit;line-height:1.4;padding:6px 8px;box-sizing:border-box;color:var(--agrid-color-text);background:var(--agrid-color-bg);box-shadow:0 8px 24px var(--agrid-color-shadow);user-select:text;-webkit-user-select:text}.ag-cell-input--formula{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;color:var(--agrid-color-accent-fg);background:var(--agrid-color-accent-subtle)}.ag-rich-select-editor{position:absolute;z-index:8;top:0;left:0;width:min(320px,max(100%,240px));color:var(--agrid-color-text);background:var(--agrid-color-bg);border:1px solid var(--agrid-color-accent);box-shadow:0 8px 24px var(--agrid-color-shadow)}.ag-rich-select-input{height:32px;border-bottom:1px solid var(--agrid-color-border)}.ag-rich-select-panel{max-height:180px;overflow:auto;padding:3px;background:var(--agrid-color-bg)}.ag-rich-select-option{display:block;width:100%;min-height:26px;border:0;border-radius:3px;background:transparent;color:var(--agrid-color-text);font:inherit;line-height:1.2;text-align:left;padding:4px 7px;cursor:pointer}.ag-rich-select-option:hover,.ag-rich-select-option--active{background:var(--agrid-color-accent-subtle);color:var(--agrid-color-accent-fg)}.ag-rich-select-empty{padding:7px;color:var(--agrid-color-text-muted);font-size:12px;line-height:1.3}.ag-cell-checkbox{display:block;margin:9px auto;cursor:pointer;accent-color:var(--agrid-color-accent)}.ag-cell-checkbox:disabled{cursor:not-allowed;opacity:.6}.ag-cell-input--invalid{outline:2px solid var(--agrid-color-danger);outline-offset:-2px}.ag-cell-error{position:absolute;left:0;top:100%;z-index:5;max-width:240px;padding:3px 8px;font-size:12px;line-height:1.4;white-space:normal;color:#fff;background:var(--agrid-color-danger);border-radius:0 0 4px 4px;box-shadow:0 2px 6px #0000002e;pointer-events:none}\n"] }]
|
|
1672
|
+
}], ctorParameters: () => [], propDecorators: { localeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "localeText", required: false }] }], col: [{ type: i0.Input, args: [{ isSignal: true, alias: "col", required: true }] }], paneColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "paneColumns", required: false }] }], paneHasSpans: [{ type: i0.Input, args: [{ isSignal: true, alias: "paneHasSpans", required: false }] }], rowIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowIndex", required: true }] }], colIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "colIndex", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], displayValueOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayValueOverride", required: false }] }], row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], editing: [{ type: i0.Input, args: [{ isSignal: true, alias: "editing", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], showInfoIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showInfoIcon", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], treeCell: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeCell", required: false }] }], treeLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeLevel", required: false }] }], treeExpandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeExpandable", required: false }] }], treeExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeExpanded", required: false }] }], treeToggle: [{ type: i0.Output, args: ["treeToggle"] }], seedChar: [{ type: i0.Input, args: [{ isSignal: true, alias: "seedChar", required: false }] }], selectTextOnEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectTextOnEdit", required: false }] }], activate: [{ type: i0.Output, args: ["activate"] }], startEdit: [{ type: i0.Output, args: ["startEdit"] }], booleanToggle: [{ type: i0.Output, args: ["booleanToggle"] }], infoClick: [{ type: i0.Output, args: ["infoClick"] }], draftChange: [{ type: i0.Output, args: ["draftChange"] }], editorCommit: [{ type: i0.Output, args: ["editorCommit"] }], editorCancel: [{ type: i0.Output, args: ["editorCancel"] }], inputEl: [{ type: i0.ViewChild, args: ['editInput', { isSignal: true }] }], selectEl: [{ type: i0.ViewChild, args: ['editSelect', { isSignal: true }] }], largeTextEl: [{ type: i0.ViewChild, args: ['largeTextInput', { isSignal: true }] }], richSelectEl: [{ type: i0.ViewChild, args: ['richSelectInput', { isSignal: true }] }] } });
|
|
1393
1673
|
|
|
1394
1674
|
/**
|
|
1395
1675
|
* Renders the grouped-header row, header-cell row, and inline filter row for a single grid pane.
|
|
@@ -1622,7 +1902,7 @@ class AgridClipboardHandler {
|
|
|
1622
1902
|
const col = cols[colIndex];
|
|
1623
1903
|
if (!col)
|
|
1624
1904
|
continue;
|
|
1625
|
-
cells.push(this.escapeTsvValue(getDisplayForField(col, row[col.field], this.opts.locale())));
|
|
1905
|
+
cells.push(this.escapeTsvValue(getDisplayForField(col, row[col.field], this.opts.locale(), row)));
|
|
1626
1906
|
}
|
|
1627
1907
|
return cells.join('\t');
|
|
1628
1908
|
}
|
|
@@ -1926,8 +2206,7 @@ class AgridColumnVirtualizationController {
|
|
|
1926
2206
|
window = computed(() => {
|
|
1927
2207
|
const widths = this.opts.columnWidths();
|
|
1928
2208
|
const count = widths.length;
|
|
1929
|
-
|
|
1930
|
-
if (count <= this.opts.minColumns() || viewportWidth <= 0) {
|
|
2209
|
+
if (count <= this.opts.minColumns()) {
|
|
1931
2210
|
return { start: 0, end: count, leftWidth: 0, rightWidth: 0 };
|
|
1932
2211
|
}
|
|
1933
2212
|
// prefix[i] is the left edge of column i; prefix[count] is the total width.
|
|
@@ -1937,6 +2216,9 @@ class AgridColumnVirtualizationController {
|
|
|
1937
2216
|
prefix[i + 1] = prefix[i] + widths[i];
|
|
1938
2217
|
const total = prefix[count];
|
|
1939
2218
|
const scrollLeft = this.opts.scrollLeft();
|
|
2219
|
+
const viewportWidth = this.opts.viewportWidth() > 0
|
|
2220
|
+
? this.opts.viewportWidth()
|
|
2221
|
+
: this.overscanPx * 4;
|
|
1940
2222
|
const min = scrollLeft - this.overscanPx;
|
|
1941
2223
|
const max = scrollLeft + viewportWidth + this.overscanPx;
|
|
1942
2224
|
// First column whose right edge crosses the (overscanned) left boundary.
|
|
@@ -1955,6 +2237,13 @@ class AgridColumnVirtualizationController {
|
|
|
1955
2237
|
}, ...(ngDevMode ? [{ debugName: "window" }] : /* istanbul ignore next */ []));
|
|
1956
2238
|
}
|
|
1957
2239
|
|
|
2240
|
+
/**
|
|
2241
|
+
* DI token a custom {@link ColDef.filterComponent} injects to control column filtering.
|
|
2242
|
+
*
|
|
2243
|
+
* The token is only available while the component is rendered inside an aGrid column menu.
|
|
2244
|
+
*/
|
|
2245
|
+
const AGRID_FILTER_CONTEXT = new InjectionToken('AGRID_FILTER_CONTEXT');
|
|
2246
|
+
|
|
1958
2247
|
/** Clamp a floating menu so it remains inside the browser viewport. @internal */
|
|
1959
2248
|
function fitColumnMenuToViewport(x, y, width, height, viewportWidth, viewportHeight, margin = 8) {
|
|
1960
2249
|
return {
|
|
@@ -1966,6 +2255,7 @@ function fitColumnMenuToViewport(x, y, width, height, viewportWidth, viewportHei
|
|
|
1966
2255
|
class AgridColumnMenuComponent {
|
|
1967
2256
|
elementRef = inject(ElementRef);
|
|
1968
2257
|
destroyRef = inject(DestroyRef);
|
|
2258
|
+
injector = inject(Injector);
|
|
1969
2259
|
browser = new AgridBrowserAdapter();
|
|
1970
2260
|
resizeObserver = null;
|
|
1971
2261
|
/** Localized labels used in the menu. */
|
|
@@ -1998,6 +2288,14 @@ class AgridColumnMenuComponent {
|
|
|
1998
2288
|
grouped = input(false, ...(ngDevMode ? [{ debugName: "grouped" }] : /* istanbul ignore next */ []));
|
|
1999
2289
|
/** Whether the active column supports value-filter controls. */
|
|
2000
2290
|
filterable = input(false, ...(ngDevMode ? [{ debugName: "filterable" }] : /* istanbul ignore next */ []));
|
|
2291
|
+
/** Column definition for custom filter components. */
|
|
2292
|
+
column = input(null, ...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
|
|
2293
|
+
/** Shared control that owns the active filter state. */
|
|
2294
|
+
control = input(null, ...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
|
|
2295
|
+
/** Current filter snapshot for the active column. */
|
|
2296
|
+
filter = input({ text: '', selectedValues: null, sort: null }, ...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
|
|
2297
|
+
/** Emits a complete filter replacement from a custom filter component. */
|
|
2298
|
+
filterReplace = output();
|
|
2001
2299
|
/** Whether clear-filter commands are shown above the condition controls. */
|
|
2002
2300
|
showFilterActions = input(true, ...(ngDevMode ? [{ debugName: "showFilterActions" }] : /* istanbul ignore next */ []));
|
|
2003
2301
|
/** Whether to show the Excel-style distinct-value picker. */
|
|
@@ -2101,6 +2399,26 @@ class AgridColumnMenuComponent {
|
|
|
2101
2399
|
}, ...(ngDevMode ? [{ debugName: "operatorOptions" }] : /* istanbul ignore next */ []));
|
|
2102
2400
|
/** Native input type for operand fields (date columns use a date picker). */
|
|
2103
2401
|
operandInputType = computed(() => this.filterType() === 'date' ? 'date' : this.filterType() === 'number' ? 'number' : 'text', ...(ngDevMode ? [{ debugName: "operandInputType" }] : /* istanbul ignore next */ []));
|
|
2402
|
+
customFilterInjector = computed(() => {
|
|
2403
|
+
const column = this.column();
|
|
2404
|
+
if (!column?.filterComponent)
|
|
2405
|
+
return null;
|
|
2406
|
+
const context = {
|
|
2407
|
+
field: column.field,
|
|
2408
|
+
column,
|
|
2409
|
+
control: this.control(),
|
|
2410
|
+
filter: computed(() => this.filter()),
|
|
2411
|
+
setFilter: filter => this.filterReplace.emit(filter),
|
|
2412
|
+
clear: () => this.clearFilter.emit(),
|
|
2413
|
+
close: () => this.close.emit(),
|
|
2414
|
+
};
|
|
2415
|
+
return Injector.create({
|
|
2416
|
+
providers: [{ provide: AGRID_FILTER_CONTEXT, useValue: context }],
|
|
2417
|
+
parent: this.injector,
|
|
2418
|
+
});
|
|
2419
|
+
}, ...(ngDevMode ? [{ debugName: "customFilterInjector" }] : /* istanbul ignore next */ []));
|
|
2420
|
+
/** Requests closing the menu after a custom filter action. */
|
|
2421
|
+
close = output();
|
|
2104
2422
|
constructor() {
|
|
2105
2423
|
effect(() => {
|
|
2106
2424
|
this.position.set({ x: this.x(), y: this.y() });
|
|
@@ -2130,12 +2448,12 @@ class AgridColumnMenuComponent {
|
|
|
2130
2448
|
return this.elementRef.nativeElement.querySelector('.ag-filter-menu');
|
|
2131
2449
|
}
|
|
2132
2450
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridColumnMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2133
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridColumnMenuComponent, isStandalone: true, selector: "agrid-column-menu", inputs: { localeText: { classPropertyName: "localeText", publicName: "localeText", isSignal: true, isRequired: false, transformFunction: null }, x: { classPropertyName: "x", publicName: "x", isSignal: true, isRequired: true, transformFunction: null }, y: { classPropertyName: "y", publicName: "y", isSignal: true, isRequired: true, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: true, transformFunction: null }, sortDir: { classPropertyName: "sortDir", publicName: "sortDir", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, showColumnActions: { classPropertyName: "showColumnActions", publicName: "showColumnActions", isSignal: true, isRequired: false, transformFunction: null }, showAggregationActions: { classPropertyName: "showAggregationActions", publicName: "showAggregationActions", isSignal: true, isRequired: false, transformFunction: null }, customItems: { classPropertyName: "customItems", publicName: "customItems", isSignal: true, isRequired: false, transformFunction: null }, pinned: { classPropertyName: "pinned", publicName: "pinned", isSignal: true, isRequired: false, transformFunction: null }, groupable: { classPropertyName: "groupable", publicName: "groupable", isSignal: true, isRequired: false, transformFunction: null }, grouped: { classPropertyName: "grouped", publicName: "grouped", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, showFilterActions: { classPropertyName: "showFilterActions", publicName: "showFilterActions", isSignal: true, isRequired: false, transformFunction: null }, showValueFilter: { classPropertyName: "showValueFilter", publicName: "showValueFilter", isSignal: true, isRequired: false, transformFunction: null }, filterType: { classPropertyName: "filterType", publicName: "filterType", isSignal: true, isRequired: false, transformFunction: null }, operator: { classPropertyName: "operator", publicName: "operator", isSignal: true, isRequired: false, transformFunction: null }, operand: { classPropertyName: "operand", publicName: "operand", isSignal: true, isRequired: false, transformFunction: null }, operand2: { classPropertyName: "operand2", publicName: "operand2", isSignal: true, isRequired: false, transformFunction: null }, search: { classPropertyName: "search", publicName: "search", isSignal: true, isRequired: false, transformFunction: null }, allSelected: { classPropertyName: "allSelected", publicName: "allSelected", isSignal: true, isRequired: false, transformFunction: null }, valueItems: { classPropertyName: "valueItems", publicName: "valueItems", isSignal: true, isRequired: false, transformFunction: null }, sortPriority: { classPropertyName: "sortPriority", publicName: "sortPriority", isSignal: true, isRequired: false, transformFunction: null }, hasMultiSort: { classPropertyName: "hasMultiSort", publicName: "hasMultiSort", isSignal: true, isRequired: false, transformFunction: null }, aggregate: { classPropertyName: "aggregate", publicName: "aggregate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customAction: "customAction", operatorChange: "operatorChange", operandChange: "operandChange", operand2Change: "operand2Change", sort: "sort", resetSort: "resetSort", autosize: "autosize", togglePin: "togglePin", togglePinRight: "togglePinRight", hide: "hide", toggleGroup: "toggleGroup", clearFilter: "clearFilter", clearAll: "clearAll", searchChange: "searchChange", toggleAll: "toggleAll", toggleValue: "toggleValue", setAggregate: "setAggregate" }, ngImport: i0, template: "<div\n class=\"ag-filter-menu\"\n role=\"dialog\"\n [attr.aria-label]=\"localeText().columnMenu + ': ' + header()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n (click)=\"$event.stopPropagation()\"\n>\n @if (sortable()) {\n <div class=\"ag-filter-menu-section\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'asc'\"\n (click)=\"sort.emit('asc')\"\n >\n \u2191 {{ localeText().sortAscending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'desc'\"\n (click)=\"sort.emit('desc')\"\n >\n \u2193 {{ localeText().sortDescending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n @if (hasMultiSort() && sortPriority() > 0) {\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"resetSort.emit(sortDir()!)\">{{ localeText().sortOnlyByThis }}</button>\n }\n @if (sortDir()) {\n <button class=\"ag-filter-menu-item\" (click)=\"sort.emit(sortDir()!)\">{{ localeText().clearSort }}</button>\n }\n </div>\n }\n\n @if (showColumnActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item\" (click)=\"autosize.emit()\">\u2194 {{ localeText().autosizeColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'left'\"\n (click)=\"togglePin.emit()\"\n >\u22A3 {{ pinned() === 'left' ? localeText().unpinColumn : localeText().pinColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'right'\"\n (click)=\"togglePinRight.emit()\"\n >\u22A2 {{ pinned() === 'right' ? localeText().unpinColumnRight : localeText().pinColumnRight }}</button>\n <button class=\"ag-filter-menu-item\" (click)=\"hide.emit()\">{{ localeText().hideColumn }}</button>\n </div>\n }\n\n @if (showColumnActions() && showAggregationActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().aggregate }}</span>\n <div class=\"ag-filter-menu-aggregate-btns\">\n @for (opt of aggregateOptions(); track opt.value) {\n <button\n class=\"ag-aggregate-btn\"\n [class.ag-aggregate-btn--active]=\"aggregate() === opt.value\"\n [title]=\"opt.label\"\n (click)=\"setAggregate.emit(aggregate() === opt.value ? null : opt.value)\"\n >{{ opt.symbol }}</button>\n }\n </div>\n </div>\n }\n\n @if (customItems().length > 0) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-custom\">\n @for (item of customItems(); track item.key) {\n <button type=\"button\" [class]=\"[... item.itemClasses??[], ...['ag-filter-menu-item'] ].join(' ')\" [disabled]=\"item.disabled\"\n [attr.data-command-key]=\"item.key\" (click)=\"customAction.emit(item.key)\">\n @if (item.icon) { <span [class]=\"[...item.iconClasses??[] , ... ['ag-filter-menu-item-icon']].join(' ')\" >{{ item.icon }}</span> }\n {{ item.label }}\n </button>\n }\n </div>\n }\n\n @if (groupable()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"grouped()\"\n (click)=\"toggleGroup.emit()\"\n >{{ grouped() ? '\u229F ' + localeText().ungroup : '\u229E ' + localeText().groupBy(header()) }}</button>\n </div>\n }\n\n @if (filterable()) {\n @if (showFilterActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearFilter.emit()\">\n \u2715 {{ localeText().clearFilter }}\n </button>\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearAll.emit()\">\n \u2715 {{ localeText().clearAllFilters }}\n </button>\n </div>\n }\n\n @if (filterType()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-condition\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().filterCondition }}</span>\n <div class=\"ag-filter-menu-operators\">\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn ag-filter-menu-operator-btn--clear\"\n [class.ag-filter-menu-operator-btn--active]=\"!operator()\"\n (click)=\"operatorChange.emit(null)\"\n >{{ localeText().filterNoCondition }}</button>\n @for (op of operatorOptions(); track op.value) {\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn\"\n [class.ag-filter-menu-operator-btn--active]=\"op.value === operator()\"\n (click)=\"operatorChange.emit(op.value)\"\n >{{ op.label }}</button>\n }\n </div>\n @if (operator()) {\n <label class=\"ag-filter-menu-operand-label\" for=\"agrid-filter-operand\">\n {{ localeText().filterValue }}\n </label>\n <input\n id=\"agrid-filter-operand\"\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand()\"\n (input)=\"operandChange.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n @if (operator() === 'between') {\n <input\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand2()\"\n (input)=\"operand2Change.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n }\n </div>\n }\n\n @if (showValueFilter()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <input\n class=\"ag-filter-menu-search\"\n [value]=\"search()\"\n (input)=\"searchChange.emit($any($event.target).value)\"\n [placeholder]=\"localeText().searchValuesPlaceholder\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n\n <div class=\"ag-filter-menu-values\">\n <label class=\"ag-filter-menu-value\">\n <input\n type=\"checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleAll.emit()\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ localeText().selectAll }}</span>\n </label>\n @for (item of valueItems(); track item.rawStr) {\n <label\n class=\"ag-filter-menu-value\"\n [class.ag-filter-menu-value--inactive]=\"!item.active\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"item.selected\"\n [disabled]=\"!item.active\"\n (change)=\"toggleValue.emit(item.rawStr)\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ item.label || localeText().blank }}</span>\n </label>\n }\n </div>\n }\n }\n</div>\n", styles: [".ag-filter-menu{position:fixed;z-index:1001;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:200px;max-height:calc(100vh - 16px);font-size:13px;overflow-y:auto}.ag-filter-menu-section{padding:4px 0}.ag-filter-menu-section--border{border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-item{display:block;width:100%;padding:5px 14px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit;font-size:12px}.ag-filter-menu-item:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-item--active{color:var(--agrid-color-accent);font-weight:600}.ag-filter-menu-item--muted{color:var(--agrid-color-text-muted)}.ag-filter-menu-item--muted:hover{background:var(--mat-toolbar-container-background-color);color:var(--agrid-color-text-muted);cursor:not-allowed}.ag-filter-menu-search{background:var(--agrid-color-bg-subtle);display:block;width:calc(100% - 16px);margin:0 8px;height:24px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 6px}.ag-filter-menu-search:focus{border-color:var(--agrid-color-accent)}.ag-filter-menu-values{max-height:120px;overflow-y:auto;padding:4px 0;border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-value{display:flex;align-items:center;gap:6px;padding:3px 14px;cursor:pointer;font-size:12px}.ag-filter-menu-value:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-value input[type=checkbox]{cursor:pointer;margin:0}.ag-filter-menu-value--inactive{opacity:.38;cursor:default}.ag-filter-menu-value--inactive input[type=checkbox]{cursor:not-allowed}.ag-filter-menu-value-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-sort-priority-badge{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--agrid-color-accent);color:#fff;font-size:9px;font-weight:700;margin-left:auto}.ag-filter-menu-aggregate-label{display:block;padding:4px 14px 2px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--agrid-color-text-muted);-webkit-user-select:none;user-select:none}.ag-filter-menu-aggregate-btns{display:flex;gap:4px;padding:2px 14px 6px}.ag-aggregate-btn{flex:1;height:26px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text-muted);font-size:13px;cursor:pointer;padding:0;transition:background 80ms,color 80ms}.ag-aggregate-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text);border-color:var(--agrid-color-text-muted)}.ag-aggregate-btn--active{background:var(--agrid-color-accent-subtle);border-color:var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-weight:700}.ag-filter-menu-condition{display:flex;flex-direction:column;gap:6px;padding:6px 14px 8px}.ag-filter-menu-operand{height:28px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;padding:0 8px;box-sizing:border-box;width:100%}.ag-filter-menu-operand:focus{outline:none;border-color:var(--agrid-color-accent-border)}.ag-filter-menu-operators{display:grid;grid-template-columns:1fr 1fr;gap:4px}.ag-filter-menu-operator-btn{min-height:26px;padding:3px 6px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:11px;line-height:1.15;text-align:left;cursor:pointer}.ag-filter-menu-operator-btn:hover,.ag-filter-menu-operator-btn:focus-visible{border-color:var(--agrid-color-accent-border);outline:none}.ag-filter-menu-operator-btn--active{border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle);color:var(--agrid-color-accent-fg)}.ag-filter-menu-operator-btn--clear{grid-column:1 / -1}.ag-filter-menu-operand-label{font-size:11px;color:var(--agrid-color-text-muted)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2451
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridColumnMenuComponent, isStandalone: true, selector: "agrid-column-menu", inputs: { localeText: { classPropertyName: "localeText", publicName: "localeText", isSignal: true, isRequired: false, transformFunction: null }, x: { classPropertyName: "x", publicName: "x", isSignal: true, isRequired: true, transformFunction: null }, y: { classPropertyName: "y", publicName: "y", isSignal: true, isRequired: true, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: true, transformFunction: null }, sortDir: { classPropertyName: "sortDir", publicName: "sortDir", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, showColumnActions: { classPropertyName: "showColumnActions", publicName: "showColumnActions", isSignal: true, isRequired: false, transformFunction: null }, showAggregationActions: { classPropertyName: "showAggregationActions", publicName: "showAggregationActions", isSignal: true, isRequired: false, transformFunction: null }, customItems: { classPropertyName: "customItems", publicName: "customItems", isSignal: true, isRequired: false, transformFunction: null }, pinned: { classPropertyName: "pinned", publicName: "pinned", isSignal: true, isRequired: false, transformFunction: null }, groupable: { classPropertyName: "groupable", publicName: "groupable", isSignal: true, isRequired: false, transformFunction: null }, grouped: { classPropertyName: "grouped", publicName: "grouped", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: false, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, showFilterActions: { classPropertyName: "showFilterActions", publicName: "showFilterActions", isSignal: true, isRequired: false, transformFunction: null }, showValueFilter: { classPropertyName: "showValueFilter", publicName: "showValueFilter", isSignal: true, isRequired: false, transformFunction: null }, filterType: { classPropertyName: "filterType", publicName: "filterType", isSignal: true, isRequired: false, transformFunction: null }, operator: { classPropertyName: "operator", publicName: "operator", isSignal: true, isRequired: false, transformFunction: null }, operand: { classPropertyName: "operand", publicName: "operand", isSignal: true, isRequired: false, transformFunction: null }, operand2: { classPropertyName: "operand2", publicName: "operand2", isSignal: true, isRequired: false, transformFunction: null }, search: { classPropertyName: "search", publicName: "search", isSignal: true, isRequired: false, transformFunction: null }, allSelected: { classPropertyName: "allSelected", publicName: "allSelected", isSignal: true, isRequired: false, transformFunction: null }, valueItems: { classPropertyName: "valueItems", publicName: "valueItems", isSignal: true, isRequired: false, transformFunction: null }, sortPriority: { classPropertyName: "sortPriority", publicName: "sortPriority", isSignal: true, isRequired: false, transformFunction: null }, hasMultiSort: { classPropertyName: "hasMultiSort", publicName: "hasMultiSort", isSignal: true, isRequired: false, transformFunction: null }, aggregate: { classPropertyName: "aggregate", publicName: "aggregate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customAction: "customAction", filterReplace: "filterReplace", operatorChange: "operatorChange", operandChange: "operandChange", operand2Change: "operand2Change", sort: "sort", resetSort: "resetSort", autosize: "autosize", togglePin: "togglePin", togglePinRight: "togglePinRight", hide: "hide", toggleGroup: "toggleGroup", clearFilter: "clearFilter", clearAll: "clearAll", searchChange: "searchChange", toggleAll: "toggleAll", toggleValue: "toggleValue", setAggregate: "setAggregate", close: "close" }, ngImport: i0, template: "<div\n class=\"ag-filter-menu\"\n role=\"dialog\"\n [attr.aria-label]=\"localeText().columnMenu + ': ' + header()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n (click)=\"$event.stopPropagation()\"\n>\n @if (sortable()) {\n <div class=\"ag-filter-menu-section\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'asc'\"\n (click)=\"sort.emit('asc')\"\n >\n \u2191 {{ localeText().sortAscending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'desc'\"\n (click)=\"sort.emit('desc')\"\n >\n \u2193 {{ localeText().sortDescending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n @if (hasMultiSort() && sortPriority() > 0) {\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"resetSort.emit(sortDir()!)\">{{ localeText().sortOnlyByThis }}</button>\n }\n @if (sortDir()) {\n <button class=\"ag-filter-menu-item\" (click)=\"sort.emit(sortDir()!)\">{{ localeText().clearSort }}</button>\n }\n </div>\n }\n\n @if (showColumnActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item\" (click)=\"autosize.emit()\">\u2194 {{ localeText().autosizeColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'left'\"\n (click)=\"togglePin.emit()\"\n >\u22A3 {{ pinned() === 'left' ? localeText().unpinColumn : localeText().pinColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'right'\"\n (click)=\"togglePinRight.emit()\"\n >\u22A2 {{ pinned() === 'right' ? localeText().unpinColumnRight : localeText().pinColumnRight }}</button>\n <button class=\"ag-filter-menu-item\" (click)=\"hide.emit()\">{{ localeText().hideColumn }}</button>\n </div>\n }\n\n @if (showColumnActions() && showAggregationActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().aggregate }}</span>\n <div class=\"ag-filter-menu-aggregate-btns\">\n @for (opt of aggregateOptions(); track opt.value) {\n <button\n class=\"ag-aggregate-btn\"\n [class.ag-aggregate-btn--active]=\"aggregate() === opt.value\"\n [title]=\"opt.label\"\n (click)=\"setAggregate.emit(aggregate() === opt.value ? null : opt.value)\"\n >{{ opt.symbol }}</button>\n }\n </div>\n </div>\n }\n\n @if (customItems().length > 0) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-custom\">\n @for (item of customItems(); track item.key) {\n <button type=\"button\" [class]=\"[... item.itemClasses??[], ...['ag-filter-menu-item'] ].join(' ')\" [disabled]=\"item.disabled\"\n [attr.data-command-key]=\"item.key\" (click)=\"customAction.emit(item.key)\">\n @if (item.icon) { <span [class]=\"[...item.iconClasses??[] , ... ['ag-filter-menu-item-icon']].join(' ')\" >{{ item.icon }}</span> }\n {{ item.label }}\n </button>\n }\n </div>\n }\n\n @if (groupable()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"grouped()\"\n (click)=\"toggleGroup.emit()\"\n >{{ grouped() ? '\u229F ' + localeText().ungroup : '\u229E ' + localeText().groupBy(header()) }}</button>\n </div>\n }\n\n @if (filterable()) {\n @if (showFilterActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearFilter.emit()\">\n \u2715 {{ localeText().clearFilter }}\n </button>\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearAll.emit()\">\n \u2715 {{ localeText().clearAllFilters }}\n </button>\n </div>\n }\n\n @if (filterType()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-condition\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().filterCondition }}</span>\n <div class=\"ag-filter-menu-operators\">\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn ag-filter-menu-operator-btn--clear\"\n [class.ag-filter-menu-operator-btn--active]=\"!operator()\"\n (click)=\"operatorChange.emit(null)\"\n >{{ localeText().filterNoCondition }}</button>\n @for (op of operatorOptions(); track op.value) {\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn\"\n [class.ag-filter-menu-operator-btn--active]=\"op.value === operator()\"\n (click)=\"operatorChange.emit(op.value)\"\n >{{ op.label }}</button>\n }\n </div>\n @if (operator()) {\n <label class=\"ag-filter-menu-operand-label\" for=\"agrid-filter-operand\">\n {{ localeText().filterValue }}\n </label>\n <input\n id=\"agrid-filter-operand\"\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand()\"\n (input)=\"operandChange.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n @if (operator() === 'between') {\n <input\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand2()\"\n (input)=\"operand2Change.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n }\n </div>\n }\n\n @if (column()?.filterComponent && customFilterInjector(); as customInjector) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-custom-filter\">\n <ng-container *ngComponentOutlet=\"column()!.filterComponent ?? null; injector: customInjector\" />\n </div>\n }\n\n @if (showValueFilter()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <input\n class=\"ag-filter-menu-search\"\n [value]=\"search()\"\n (input)=\"searchChange.emit($any($event.target).value)\"\n [placeholder]=\"localeText().searchValuesPlaceholder\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n\n <div class=\"ag-filter-menu-values\">\n <label class=\"ag-filter-menu-value\">\n <input\n type=\"checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleAll.emit()\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ localeText().selectAll }}</span>\n </label>\n @for (item of valueItems(); track item.rawStr) {\n <label\n class=\"ag-filter-menu-value\"\n [class.ag-filter-menu-value--inactive]=\"!item.active\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"item.selected\"\n [disabled]=\"!item.active\"\n (change)=\"toggleValue.emit(item.rawStr)\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ item.label || localeText().blank }}</span>\n </label>\n }\n </div>\n }\n }\n</div>\n", styles: [".ag-filter-menu{position:fixed;z-index:1001;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:200px;max-height:calc(100vh - 16px);font-size:13px;overflow-y:auto}.ag-filter-menu-section{padding:4px 0}.ag-filter-menu-section--border{border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-item{display:block;width:100%;padding:5px 14px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit;font-size:12px}.ag-filter-menu-item:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-item--active{color:var(--agrid-color-accent);font-weight:600}.ag-filter-menu-item--muted{color:var(--agrid-color-text-muted)}.ag-filter-menu-item--muted:hover{background:var(--mat-toolbar-container-background-color);color:var(--agrid-color-text-muted);cursor:not-allowed}.ag-filter-menu-search{background:var(--agrid-color-bg-subtle);display:block;width:calc(100% - 16px);margin:0 8px;height:24px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 6px}.ag-filter-menu-search:focus{border-color:var(--agrid-color-accent)}.ag-filter-menu-values{max-height:120px;overflow-y:auto;padding:4px 0;border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-value{display:flex;align-items:center;gap:6px;padding:3px 14px;cursor:pointer;font-size:12px}.ag-filter-menu-value:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-value input[type=checkbox]{cursor:pointer;margin:0}.ag-filter-menu-value--inactive{opacity:.38;cursor:default}.ag-filter-menu-value--inactive input[type=checkbox]{cursor:not-allowed}.ag-filter-menu-value-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-sort-priority-badge{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--agrid-color-accent);color:#fff;font-size:9px;font-weight:700;margin-left:auto}.ag-filter-menu-aggregate-label{display:block;padding:4px 14px 2px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--agrid-color-text-muted);-webkit-user-select:none;user-select:none}.ag-filter-menu-aggregate-btns{display:flex;gap:4px;padding:2px 14px 6px}.ag-aggregate-btn{flex:1;height:26px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text-muted);font-size:13px;cursor:pointer;padding:0;transition:background 80ms,color 80ms}.ag-aggregate-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text);border-color:var(--agrid-color-text-muted)}.ag-aggregate-btn--active{background:var(--agrid-color-accent-subtle);border-color:var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-weight:700}.ag-filter-menu-condition{display:flex;flex-direction:column;gap:6px;padding:6px 14px 8px}.ag-filter-menu-operand{height:28px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;padding:0 8px;box-sizing:border-box;width:100%}.ag-filter-menu-operand:focus{outline:none;border-color:var(--agrid-color-accent-border)}.ag-filter-menu-operators{display:grid;grid-template-columns:1fr 1fr;gap:4px}.ag-filter-menu-operator-btn{min-height:26px;padding:3px 6px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:11px;line-height:1.15;text-align:left;cursor:pointer}.ag-filter-menu-operator-btn:hover,.ag-filter-menu-operator-btn:focus-visible{border-color:var(--agrid-color-accent-border);outline:none}.ag-filter-menu-operator-btn--active{border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle);color:var(--agrid-color-accent-fg)}.ag-filter-menu-operator-btn--clear{grid-column:1 / -1}.ag-filter-menu-operand-label{font-size:11px;color:var(--agrid-color-text-muted)}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2134
2452
|
}
|
|
2135
2453
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridColumnMenuComponent, decorators: [{
|
|
2136
2454
|
type: Component,
|
|
2137
|
-
args: [{ selector: 'agrid-column-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ag-filter-menu\"\n role=\"dialog\"\n [attr.aria-label]=\"localeText().columnMenu + ': ' + header()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n (click)=\"$event.stopPropagation()\"\n>\n @if (sortable()) {\n <div class=\"ag-filter-menu-section\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'asc'\"\n (click)=\"sort.emit('asc')\"\n >\n \u2191 {{ localeText().sortAscending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'desc'\"\n (click)=\"sort.emit('desc')\"\n >\n \u2193 {{ localeText().sortDescending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n @if (hasMultiSort() && sortPriority() > 0) {\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"resetSort.emit(sortDir()!)\">{{ localeText().sortOnlyByThis }}</button>\n }\n @if (sortDir()) {\n <button class=\"ag-filter-menu-item\" (click)=\"sort.emit(sortDir()!)\">{{ localeText().clearSort }}</button>\n }\n </div>\n }\n\n @if (showColumnActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item\" (click)=\"autosize.emit()\">\u2194 {{ localeText().autosizeColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'left'\"\n (click)=\"togglePin.emit()\"\n >\u22A3 {{ pinned() === 'left' ? localeText().unpinColumn : localeText().pinColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'right'\"\n (click)=\"togglePinRight.emit()\"\n >\u22A2 {{ pinned() === 'right' ? localeText().unpinColumnRight : localeText().pinColumnRight }}</button>\n <button class=\"ag-filter-menu-item\" (click)=\"hide.emit()\">{{ localeText().hideColumn }}</button>\n </div>\n }\n\n @if (showColumnActions() && showAggregationActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().aggregate }}</span>\n <div class=\"ag-filter-menu-aggregate-btns\">\n @for (opt of aggregateOptions(); track opt.value) {\n <button\n class=\"ag-aggregate-btn\"\n [class.ag-aggregate-btn--active]=\"aggregate() === opt.value\"\n [title]=\"opt.label\"\n (click)=\"setAggregate.emit(aggregate() === opt.value ? null : opt.value)\"\n >{{ opt.symbol }}</button>\n }\n </div>\n </div>\n }\n\n @if (customItems().length > 0) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-custom\">\n @for (item of customItems(); track item.key) {\n <button type=\"button\" [class]=\"[... item.itemClasses??[], ...['ag-filter-menu-item'] ].join(' ')\" [disabled]=\"item.disabled\"\n [attr.data-command-key]=\"item.key\" (click)=\"customAction.emit(item.key)\">\n @if (item.icon) { <span [class]=\"[...item.iconClasses??[] , ... ['ag-filter-menu-item-icon']].join(' ')\" >{{ item.icon }}</span> }\n {{ item.label }}\n </button>\n }\n </div>\n }\n\n @if (groupable()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"grouped()\"\n (click)=\"toggleGroup.emit()\"\n >{{ grouped() ? '\u229F ' + localeText().ungroup : '\u229E ' + localeText().groupBy(header()) }}</button>\n </div>\n }\n\n @if (filterable()) {\n @if (showFilterActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearFilter.emit()\">\n \u2715 {{ localeText().clearFilter }}\n </button>\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearAll.emit()\">\n \u2715 {{ localeText().clearAllFilters }}\n </button>\n </div>\n }\n\n @if (filterType()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-condition\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().filterCondition }}</span>\n <div class=\"ag-filter-menu-operators\">\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn ag-filter-menu-operator-btn--clear\"\n [class.ag-filter-menu-operator-btn--active]=\"!operator()\"\n (click)=\"operatorChange.emit(null)\"\n >{{ localeText().filterNoCondition }}</button>\n @for (op of operatorOptions(); track op.value) {\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn\"\n [class.ag-filter-menu-operator-btn--active]=\"op.value === operator()\"\n (click)=\"operatorChange.emit(op.value)\"\n >{{ op.label }}</button>\n }\n </div>\n @if (operator()) {\n <label class=\"ag-filter-menu-operand-label\" for=\"agrid-filter-operand\">\n {{ localeText().filterValue }}\n </label>\n <input\n id=\"agrid-filter-operand\"\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand()\"\n (input)=\"operandChange.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n @if (operator() === 'between') {\n <input\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand2()\"\n (input)=\"operand2Change.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n }\n </div>\n }\n\n @if (showValueFilter()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <input\n class=\"ag-filter-menu-search\"\n [value]=\"search()\"\n (input)=\"searchChange.emit($any($event.target).value)\"\n [placeholder]=\"localeText().searchValuesPlaceholder\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n\n <div class=\"ag-filter-menu-values\">\n <label class=\"ag-filter-menu-value\">\n <input\n type=\"checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleAll.emit()\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ localeText().selectAll }}</span>\n </label>\n @for (item of valueItems(); track item.rawStr) {\n <label\n class=\"ag-filter-menu-value\"\n [class.ag-filter-menu-value--inactive]=\"!item.active\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"item.selected\"\n [disabled]=\"!item.active\"\n (change)=\"toggleValue.emit(item.rawStr)\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ item.label || localeText().blank }}</span>\n </label>\n }\n </div>\n }\n }\n</div>\n", styles: [".ag-filter-menu{position:fixed;z-index:1001;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:200px;max-height:calc(100vh - 16px);font-size:13px;overflow-y:auto}.ag-filter-menu-section{padding:4px 0}.ag-filter-menu-section--border{border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-item{display:block;width:100%;padding:5px 14px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit;font-size:12px}.ag-filter-menu-item:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-item--active{color:var(--agrid-color-accent);font-weight:600}.ag-filter-menu-item--muted{color:var(--agrid-color-text-muted)}.ag-filter-menu-item--muted:hover{background:var(--mat-toolbar-container-background-color);color:var(--agrid-color-text-muted);cursor:not-allowed}.ag-filter-menu-search{background:var(--agrid-color-bg-subtle);display:block;width:calc(100% - 16px);margin:0 8px;height:24px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 6px}.ag-filter-menu-search:focus{border-color:var(--agrid-color-accent)}.ag-filter-menu-values{max-height:120px;overflow-y:auto;padding:4px 0;border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-value{display:flex;align-items:center;gap:6px;padding:3px 14px;cursor:pointer;font-size:12px}.ag-filter-menu-value:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-value input[type=checkbox]{cursor:pointer;margin:0}.ag-filter-menu-value--inactive{opacity:.38;cursor:default}.ag-filter-menu-value--inactive input[type=checkbox]{cursor:not-allowed}.ag-filter-menu-value-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-sort-priority-badge{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--agrid-color-accent);color:#fff;font-size:9px;font-weight:700;margin-left:auto}.ag-filter-menu-aggregate-label{display:block;padding:4px 14px 2px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--agrid-color-text-muted);-webkit-user-select:none;user-select:none}.ag-filter-menu-aggregate-btns{display:flex;gap:4px;padding:2px 14px 6px}.ag-aggregate-btn{flex:1;height:26px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text-muted);font-size:13px;cursor:pointer;padding:0;transition:background 80ms,color 80ms}.ag-aggregate-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text);border-color:var(--agrid-color-text-muted)}.ag-aggregate-btn--active{background:var(--agrid-color-accent-subtle);border-color:var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-weight:700}.ag-filter-menu-condition{display:flex;flex-direction:column;gap:6px;padding:6px 14px 8px}.ag-filter-menu-operand{height:28px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;padding:0 8px;box-sizing:border-box;width:100%}.ag-filter-menu-operand:focus{outline:none;border-color:var(--agrid-color-accent-border)}.ag-filter-menu-operators{display:grid;grid-template-columns:1fr 1fr;gap:4px}.ag-filter-menu-operator-btn{min-height:26px;padding:3px 6px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:11px;line-height:1.15;text-align:left;cursor:pointer}.ag-filter-menu-operator-btn:hover,.ag-filter-menu-operator-btn:focus-visible{border-color:var(--agrid-color-accent-border);outline:none}.ag-filter-menu-operator-btn--active{border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle);color:var(--agrid-color-accent-fg)}.ag-filter-menu-operator-btn--clear{grid-column:1 / -1}.ag-filter-menu-operand-label{font-size:11px;color:var(--agrid-color-text-muted)}\n"] }]
|
|
2138
|
-
}], ctorParameters: () => [], propDecorators: { localeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "localeText", required: false }] }], x: [{ type: i0.Input, args: [{ isSignal: true, alias: "x", required: true }] }], y: [{ type: i0.Input, args: [{ isSignal: true, alias: "y", required: true }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: true }] }], sortDir: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDir", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], showColumnActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showColumnActions", required: false }] }], showAggregationActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAggregationActions", required: false }] }], customItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "customItems", required: false }] }], customAction: [{ type: i0.Output, args: ["customAction"] }], pinned: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinned", required: false }] }], groupable: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupable", required: false }] }], grouped: [{ type: i0.Input, args: [{ isSignal: true, alias: "grouped", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], showFilterActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilterActions", required: false }] }], showValueFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValueFilter", required: false }] }], filterType: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterType", required: false }] }], operator: [{ type: i0.Input, args: [{ isSignal: true, alias: "operator", required: false }] }], operand: [{ type: i0.Input, args: [{ isSignal: true, alias: "operand", required: false }] }], operand2: [{ type: i0.Input, args: [{ isSignal: true, alias: "operand2", required: false }] }], operatorChange: [{ type: i0.Output, args: ["operatorChange"] }], operandChange: [{ type: i0.Output, args: ["operandChange"] }], operand2Change: [{ type: i0.Output, args: ["operand2Change"] }], search: [{ type: i0.Input, args: [{ isSignal: true, alias: "search", required: false }] }], allSelected: [{ type: i0.Input, args: [{ isSignal: true, alias: "allSelected", required: false }] }], valueItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueItems", required: false }] }], sortPriority: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortPriority", required: false }] }], hasMultiSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasMultiSort", required: false }] }], sort: [{ type: i0.Output, args: ["sort"] }], resetSort: [{ type: i0.Output, args: ["resetSort"] }], autosize: [{ type: i0.Output, args: ["autosize"] }], togglePin: [{ type: i0.Output, args: ["togglePin"] }], togglePinRight: [{ type: i0.Output, args: ["togglePinRight"] }], hide: [{ type: i0.Output, args: ["hide"] }], toggleGroup: [{ type: i0.Output, args: ["toggleGroup"] }], clearFilter: [{ type: i0.Output, args: ["clearFilter"] }], clearAll: [{ type: i0.Output, args: ["clearAll"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], toggleAll: [{ type: i0.Output, args: ["toggleAll"] }], toggleValue: [{ type: i0.Output, args: ["toggleValue"] }], aggregate: [{ type: i0.Input, args: [{ isSignal: true, alias: "aggregate", required: false }] }], setAggregate: [{ type: i0.Output, args: ["setAggregate"] }] } });
|
|
2455
|
+
args: [{ selector: 'agrid-column-menu', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgComponentOutlet], template: "<div\n class=\"ag-filter-menu\"\n role=\"dialog\"\n [attr.aria-label]=\"localeText().columnMenu + ': ' + header()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n (click)=\"$event.stopPropagation()\"\n>\n @if (sortable()) {\n <div class=\"ag-filter-menu-section\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'asc'\"\n (click)=\"sort.emit('asc')\"\n >\n \u2191 {{ localeText().sortAscending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"sortDir() === 'desc'\"\n (click)=\"sort.emit('desc')\"\n >\n \u2193 {{ localeText().sortDescending }}\n @if (sortPriority() > 0) {\n <span class=\"ag-sort-priority-badge\">{{ sortPriority() }}</span>\n }\n </button>\n @if (hasMultiSort() && sortPriority() > 0) {\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"resetSort.emit(sortDir()!)\">{{ localeText().sortOnlyByThis }}</button>\n }\n @if (sortDir()) {\n <button class=\"ag-filter-menu-item\" (click)=\"sort.emit(sortDir()!)\">{{ localeText().clearSort }}</button>\n }\n </div>\n }\n\n @if (showColumnActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item\" (click)=\"autosize.emit()\">\u2194 {{ localeText().autosizeColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'left'\"\n (click)=\"togglePin.emit()\"\n >\u22A3 {{ pinned() === 'left' ? localeText().unpinColumn : localeText().pinColumn }}</button>\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"pinned() === 'right'\"\n (click)=\"togglePinRight.emit()\"\n >\u22A2 {{ pinned() === 'right' ? localeText().unpinColumnRight : localeText().pinColumnRight }}</button>\n <button class=\"ag-filter-menu-item\" (click)=\"hide.emit()\">{{ localeText().hideColumn }}</button>\n </div>\n }\n\n @if (showColumnActions() && showAggregationActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().aggregate }}</span>\n <div class=\"ag-filter-menu-aggregate-btns\">\n @for (opt of aggregateOptions(); track opt.value) {\n <button\n class=\"ag-aggregate-btn\"\n [class.ag-aggregate-btn--active]=\"aggregate() === opt.value\"\n [title]=\"opt.label\"\n (click)=\"setAggregate.emit(aggregate() === opt.value ? null : opt.value)\"\n >{{ opt.symbol }}</button>\n }\n </div>\n </div>\n }\n\n @if (customItems().length > 0) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-custom\">\n @for (item of customItems(); track item.key) {\n <button type=\"button\" [class]=\"[... item.itemClasses??[], ...['ag-filter-menu-item'] ].join(' ')\" [disabled]=\"item.disabled\"\n [attr.data-command-key]=\"item.key\" (click)=\"customAction.emit(item.key)\">\n @if (item.icon) { <span [class]=\"[...item.iconClasses??[] , ... ['ag-filter-menu-item-icon']].join(' ')\" >{{ item.icon }}</span> }\n {{ item.label }}\n </button>\n }\n </div>\n }\n\n @if (groupable()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button\n class=\"ag-filter-menu-item\"\n [class.ag-filter-menu-item--active]=\"grouped()\"\n (click)=\"toggleGroup.emit()\"\n >{{ grouped() ? '\u229F ' + localeText().ungroup : '\u229E ' + localeText().groupBy(header()) }}</button>\n </div>\n }\n\n @if (filterable()) {\n @if (showFilterActions()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearFilter.emit()\">\n \u2715 {{ localeText().clearFilter }}\n </button>\n <button class=\"ag-filter-menu-item ag-filter-menu-item--muted\" (click)=\"clearAll.emit()\">\n \u2715 {{ localeText().clearAllFilters }}\n </button>\n </div>\n }\n\n @if (filterType()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-condition\">\n <span class=\"ag-filter-menu-aggregate-label\">{{ localeText().filterCondition }}</span>\n <div class=\"ag-filter-menu-operators\">\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn ag-filter-menu-operator-btn--clear\"\n [class.ag-filter-menu-operator-btn--active]=\"!operator()\"\n (click)=\"operatorChange.emit(null)\"\n >{{ localeText().filterNoCondition }}</button>\n @for (op of operatorOptions(); track op.value) {\n <button\n type=\"button\"\n class=\"ag-filter-menu-operator-btn\"\n [class.ag-filter-menu-operator-btn--active]=\"op.value === operator()\"\n (click)=\"operatorChange.emit(op.value)\"\n >{{ op.label }}</button>\n }\n </div>\n @if (operator()) {\n <label class=\"ag-filter-menu-operand-label\" for=\"agrid-filter-operand\">\n {{ localeText().filterValue }}\n </label>\n <input\n id=\"agrid-filter-operand\"\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand()\"\n (input)=\"operandChange.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n @if (operator() === 'between') {\n <input\n class=\"ag-filter-menu-operand\"\n [type]=\"operandInputType()\"\n [value]=\"operand2()\"\n (input)=\"operand2Change.emit($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n }\n </div>\n }\n\n @if (column()?.filterComponent && customFilterInjector(); as customInjector) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border ag-filter-menu-custom-filter\">\n <ng-container *ngComponentOutlet=\"column()!.filterComponent ?? null; injector: customInjector\" />\n </div>\n }\n\n @if (showValueFilter()) {\n <div class=\"ag-filter-menu-section ag-filter-menu-section--border\">\n <input\n class=\"ag-filter-menu-search\"\n [value]=\"search()\"\n (input)=\"searchChange.emit($any($event.target).value)\"\n [placeholder]=\"localeText().searchValuesPlaceholder\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n\n <div class=\"ag-filter-menu-values\">\n <label class=\"ag-filter-menu-value\">\n <input\n type=\"checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleAll.emit()\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ localeText().selectAll }}</span>\n </label>\n @for (item of valueItems(); track item.rawStr) {\n <label\n class=\"ag-filter-menu-value\"\n [class.ag-filter-menu-value--inactive]=\"!item.active\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"item.selected\"\n [disabled]=\"!item.active\"\n (change)=\"toggleValue.emit(item.rawStr)\"\n />\n <span class=\"ag-filter-menu-value-label\">{{ item.label || localeText().blank }}</span>\n </label>\n }\n </div>\n }\n }\n</div>\n", styles: [".ag-filter-menu{position:fixed;z-index:1001;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:200px;max-height:calc(100vh - 16px);font-size:13px;overflow-y:auto}.ag-filter-menu-section{padding:4px 0}.ag-filter-menu-section--border{border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-item{display:block;width:100%;padding:5px 14px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit;font-size:12px}.ag-filter-menu-item:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-item--active{color:var(--agrid-color-accent);font-weight:600}.ag-filter-menu-item--muted{color:var(--agrid-color-text-muted)}.ag-filter-menu-item--muted:hover{background:var(--mat-toolbar-container-background-color);color:var(--agrid-color-text-muted);cursor:not-allowed}.ag-filter-menu-search{background:var(--agrid-color-bg-subtle);display:block;width:calc(100% - 16px);margin:0 8px;height:24px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 6px}.ag-filter-menu-search:focus{border-color:var(--agrid-color-accent)}.ag-filter-menu-values{max-height:120px;overflow-y:auto;padding:4px 0;border-top:1px solid var(--agrid-color-border)}.ag-filter-menu-value{display:flex;align-items:center;gap:6px;padding:3px 14px;cursor:pointer;font-size:12px}.ag-filter-menu-value:hover{background:var(--agrid-color-bg-muted)}.ag-filter-menu-value input[type=checkbox]{cursor:pointer;margin:0}.ag-filter-menu-value--inactive{opacity:.38;cursor:default}.ag-filter-menu-value--inactive input[type=checkbox]{cursor:not-allowed}.ag-filter-menu-value-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-sort-priority-badge{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--agrid-color-accent);color:#fff;font-size:9px;font-weight:700;margin-left:auto}.ag-filter-menu-aggregate-label{display:block;padding:4px 14px 2px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--agrid-color-text-muted);-webkit-user-select:none;user-select:none}.ag-filter-menu-aggregate-btns{display:flex;gap:4px;padding:2px 14px 6px}.ag-aggregate-btn{flex:1;height:26px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text-muted);font-size:13px;cursor:pointer;padding:0;transition:background 80ms,color 80ms}.ag-aggregate-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text);border-color:var(--agrid-color-text-muted)}.ag-aggregate-btn--active{background:var(--agrid-color-accent-subtle);border-color:var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-weight:700}.ag-filter-menu-condition{display:flex;flex-direction:column;gap:6px;padding:6px 14px 8px}.ag-filter-menu-operand{height:28px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;padding:0 8px;box-sizing:border-box;width:100%}.ag-filter-menu-operand:focus{outline:none;border-color:var(--agrid-color-accent-border)}.ag-filter-menu-operators{display:grid;grid-template-columns:1fr 1fr;gap:4px}.ag-filter-menu-operator-btn{min-height:26px;padding:3px 6px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:11px;line-height:1.15;text-align:left;cursor:pointer}.ag-filter-menu-operator-btn:hover,.ag-filter-menu-operator-btn:focus-visible{border-color:var(--agrid-color-accent-border);outline:none}.ag-filter-menu-operator-btn--active{border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle);color:var(--agrid-color-accent-fg)}.ag-filter-menu-operator-btn--clear{grid-column:1 / -1}.ag-filter-menu-operand-label{font-size:11px;color:var(--agrid-color-text-muted)}\n"] }]
|
|
2456
|
+
}], ctorParameters: () => [], propDecorators: { localeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "localeText", required: false }] }], x: [{ type: i0.Input, args: [{ isSignal: true, alias: "x", required: true }] }], y: [{ type: i0.Input, args: [{ isSignal: true, alias: "y", required: true }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: true }] }], sortDir: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDir", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], showColumnActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showColumnActions", required: false }] }], showAggregationActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAggregationActions", required: false }] }], customItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "customItems", required: false }] }], customAction: [{ type: i0.Output, args: ["customAction"] }], pinned: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinned", required: false }] }], groupable: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupable", required: false }] }], grouped: [{ type: i0.Input, args: [{ isSignal: true, alias: "grouped", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: false }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], filterReplace: [{ type: i0.Output, args: ["filterReplace"] }], showFilterActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilterActions", required: false }] }], showValueFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValueFilter", required: false }] }], filterType: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterType", required: false }] }], operator: [{ type: i0.Input, args: [{ isSignal: true, alias: "operator", required: false }] }], operand: [{ type: i0.Input, args: [{ isSignal: true, alias: "operand", required: false }] }], operand2: [{ type: i0.Input, args: [{ isSignal: true, alias: "operand2", required: false }] }], operatorChange: [{ type: i0.Output, args: ["operatorChange"] }], operandChange: [{ type: i0.Output, args: ["operandChange"] }], operand2Change: [{ type: i0.Output, args: ["operand2Change"] }], search: [{ type: i0.Input, args: [{ isSignal: true, alias: "search", required: false }] }], allSelected: [{ type: i0.Input, args: [{ isSignal: true, alias: "allSelected", required: false }] }], valueItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueItems", required: false }] }], sortPriority: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortPriority", required: false }] }], hasMultiSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasMultiSort", required: false }] }], sort: [{ type: i0.Output, args: ["sort"] }], resetSort: [{ type: i0.Output, args: ["resetSort"] }], autosize: [{ type: i0.Output, args: ["autosize"] }], togglePin: [{ type: i0.Output, args: ["togglePin"] }], togglePinRight: [{ type: i0.Output, args: ["togglePinRight"] }], hide: [{ type: i0.Output, args: ["hide"] }], toggleGroup: [{ type: i0.Output, args: ["toggleGroup"] }], clearFilter: [{ type: i0.Output, args: ["clearFilter"] }], clearAll: [{ type: i0.Output, args: ["clearAll"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], toggleAll: [{ type: i0.Output, args: ["toggleAll"] }], toggleValue: [{ type: i0.Output, args: ["toggleValue"] }], aggregate: [{ type: i0.Input, args: [{ isSignal: true, alias: "aggregate", required: false }] }], setAggregate: [{ type: i0.Output, args: ["setAggregate"] }], close: [{ type: i0.Output, args: ["close"] }] } });
|
|
2139
2457
|
|
|
2140
2458
|
/** Owns column-menu state, filters, sorting, and menu-triggered column mutations. @internal */
|
|
2141
2459
|
class AgridColumnMenuController {
|
|
@@ -2171,8 +2489,13 @@ class AgridColumnMenuController {
|
|
|
2171
2489
|
.sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true, sensitivity: 'base' }));
|
|
2172
2490
|
}, ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
2173
2491
|
visibleItems = computed(() => {
|
|
2492
|
+
const menu = this.menu();
|
|
2493
|
+
const col = menu ? this.getColDef(menu.field) : undefined;
|
|
2174
2494
|
const search = this.search().toLowerCase();
|
|
2175
|
-
|
|
2495
|
+
const limit = Math.max(1, Math.floor(col?.filterValueLimit ?? 250));
|
|
2496
|
+
return this.items()
|
|
2497
|
+
.filter(item => !search || item.label.toLowerCase().includes(search))
|
|
2498
|
+
.slice(0, limit);
|
|
2176
2499
|
}, ...(ngDevMode ? [{ debugName: "visibleItems" }] : /* istanbul ignore next */ []));
|
|
2177
2500
|
activeValues = computed(() => {
|
|
2178
2501
|
const menu = this.menu();
|
|
@@ -2380,6 +2703,25 @@ class AgridColumnMenuController {
|
|
|
2380
2703
|
setSearch(value) {
|
|
2381
2704
|
this.search.set(value);
|
|
2382
2705
|
}
|
|
2706
|
+
/** Replaces one field's filter state from a custom filter component. */
|
|
2707
|
+
replaceFilter(field, filter) {
|
|
2708
|
+
const control = this.opts.control();
|
|
2709
|
+
if (!control)
|
|
2710
|
+
return;
|
|
2711
|
+
control.setFilter(field, filter);
|
|
2712
|
+
if (!this.opts.serverSideFiltering())
|
|
2713
|
+
return;
|
|
2714
|
+
this.opts.onFilterChange({
|
|
2715
|
+
field,
|
|
2716
|
+
value: filter.text,
|
|
2717
|
+
selectedValues: filter.selectedValues,
|
|
2718
|
+
operator: filter.operator ?? null,
|
|
2719
|
+
operand: filter.operand ?? null,
|
|
2720
|
+
operand2: filter.operand2 ?? null,
|
|
2721
|
+
});
|
|
2722
|
+
if (filter.sort)
|
|
2723
|
+
this.opts.onSortChange({ field, direction: filter.sort });
|
|
2724
|
+
}
|
|
2383
2725
|
/** Applies or clears a sort according to the configured sorting mode. */
|
|
2384
2726
|
sort(field, direction) {
|
|
2385
2727
|
const control = this.opts.control();
|
|
@@ -2429,6 +2771,9 @@ class AgridColumnMenuController {
|
|
|
2429
2771
|
if (this.opts.serverSideFiltering()) {
|
|
2430
2772
|
if (previous.text)
|
|
2431
2773
|
this.opts.onFilterChange({ field, value: '' });
|
|
2774
|
+
if (previous.selectedValues !== null) {
|
|
2775
|
+
this.opts.onFilterChange({ field, value: '', selectedValues: null });
|
|
2776
|
+
}
|
|
2432
2777
|
if (previous.operator) {
|
|
2433
2778
|
this.opts.onFilterChange({ field, value: '', operator: null, operand: null, operand2: null });
|
|
2434
2779
|
}
|
|
@@ -2473,6 +2818,9 @@ class AgridColumnMenuController {
|
|
|
2473
2818
|
for (const [field, filter] of Object.entries(previous)) {
|
|
2474
2819
|
if (filter.text)
|
|
2475
2820
|
this.opts.onFilterChange({ field, value: '' });
|
|
2821
|
+
if (filter.selectedValues !== null) {
|
|
2822
|
+
this.opts.onFilterChange({ field, value: '', selectedValues: null });
|
|
2823
|
+
}
|
|
2476
2824
|
if (filter.operator) {
|
|
2477
2825
|
this.opts.onFilterChange({ field, value: '', operator: null, operand: null, operand2: null });
|
|
2478
2826
|
}
|
|
@@ -2487,7 +2835,9 @@ class AgridColumnMenuController {
|
|
|
2487
2835
|
const control = this.opts.control();
|
|
2488
2836
|
if (!control)
|
|
2489
2837
|
return;
|
|
2490
|
-
|
|
2838
|
+
const next = control.getFilter(field).selectedValues === null ? [] : null;
|
|
2839
|
+
control.setSelectedValues(field, next);
|
|
2840
|
+
this.emitValueServer(field, next);
|
|
2491
2841
|
}
|
|
2492
2842
|
/** Toggles one raw value in a field's value filter. */
|
|
2493
2843
|
toggleValue(field, rawStr) {
|
|
@@ -2499,7 +2849,9 @@ class AgridColumnMenuController {
|
|
|
2499
2849
|
const next = current.includes(rawStr)
|
|
2500
2850
|
? current.filter(value => value !== rawStr)
|
|
2501
2851
|
: [...current, rawStr];
|
|
2502
|
-
|
|
2852
|
+
const selectedValues = next.length === allValues.length ? null : next;
|
|
2853
|
+
control.setSelectedValues(field, selectedValues);
|
|
2854
|
+
this.emitValueServer(field, selectedValues);
|
|
2503
2855
|
}
|
|
2504
2856
|
/** Toggles left pinning for a field. */
|
|
2505
2857
|
togglePin(field) {
|
|
@@ -2552,6 +2904,11 @@ class AgridColumnMenuController {
|
|
|
2552
2904
|
clearTimeout(timer);
|
|
2553
2905
|
this.filterDebounces.delete(field);
|
|
2554
2906
|
}
|
|
2907
|
+
emitValueServer(field, selectedValues) {
|
|
2908
|
+
if (!this.opts.serverSideFiltering())
|
|
2909
|
+
return;
|
|
2910
|
+
this.opts.onFilterChange({ field, value: '', selectedValues });
|
|
2911
|
+
}
|
|
2555
2912
|
}
|
|
2556
2913
|
|
|
2557
2914
|
/** Owns column header drag/drop state and column reordering. @internal */
|
|
@@ -2863,7 +3220,7 @@ class AgridColumnSizingController {
|
|
|
2863
3220
|
for (const item of this.opts.filteredItems()) {
|
|
2864
3221
|
if (!isDataRowItem(item))
|
|
2865
3222
|
continue;
|
|
2866
|
-
values.push(getDisplayForField(col, item.row[col.field], this.opts.locale()));
|
|
3223
|
+
values.push(getDisplayForField(col, item.row[col.field], this.opts.locale(), item.row));
|
|
2867
3224
|
}
|
|
2868
3225
|
const measured = values.reduce((max, value) => Math.max(max, context.measureText(value).width), 0);
|
|
2869
3226
|
return Math.max(40, Math.min(500, Math.ceil(measured + 42)));
|
|
@@ -2956,6 +3313,7 @@ class AgridDataSource {
|
|
|
2956
3313
|
_rows = linkedSignal(() => this._linkedRows()?.() ?? [], ...(ngDevMode ? [{ debugName: "_rows" }] : /* istanbul ignore next */ []));
|
|
2957
3314
|
_writableLinkedRows = null;
|
|
2958
3315
|
_rowAdded = signal(null, ...(ngDevMode ? [{ debugName: "_rowAdded" }] : /* istanbul ignore next */ []));
|
|
3316
|
+
_unfilteredAddedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "_unfilteredAddedRows" }] : /* istanbul ignore next */ []));
|
|
2959
3317
|
_changeSequence = 0;
|
|
2960
3318
|
/**
|
|
2961
3319
|
* @param initialData Rows to seed the data source with.
|
|
@@ -2971,6 +3329,12 @@ class AgridDataSource {
|
|
|
2971
3329
|
rows = this._rows.asReadonly();
|
|
2972
3330
|
/** Latest row insertion, used by attached grids to reveal the inserted row. */
|
|
2973
3331
|
rowAdded = this._rowAdded.asReadonly();
|
|
3332
|
+
/**
|
|
3333
|
+
* Rows inserted since filters were last explicitly reapplied.
|
|
3334
|
+
* Attached grids include these rows even when they do not match active filters.
|
|
3335
|
+
* @internal
|
|
3336
|
+
*/
|
|
3337
|
+
ɵunfilteredAddedRows = this._unfilteredAddedRows.asReadonly();
|
|
2974
3338
|
/**
|
|
2975
3339
|
* Link an external row signal to this data source.
|
|
2976
3340
|
*
|
|
@@ -2990,6 +3354,7 @@ class AgridDataSource {
|
|
|
2990
3354
|
*/
|
|
2991
3355
|
setData(rows) {
|
|
2992
3356
|
this.setRows([...rows]);
|
|
3357
|
+
this.ɵreapplyFiltersToAddedRows();
|
|
2993
3358
|
}
|
|
2994
3359
|
/**
|
|
2995
3360
|
* Overwrite the row at `index` with a new row object.
|
|
@@ -3032,6 +3397,13 @@ class AgridDataSource {
|
|
|
3032
3397
|
next.splice(atIndex, 0, row);
|
|
3033
3398
|
return next;
|
|
3034
3399
|
});
|
|
3400
|
+
this._unfilteredAddedRows.update(current => {
|
|
3401
|
+
const next = new Set();
|
|
3402
|
+
for (const index of current)
|
|
3403
|
+
next.add(index >= insertedAt ? index + 1 : index);
|
|
3404
|
+
next.add(insertedAt);
|
|
3405
|
+
return next;
|
|
3406
|
+
});
|
|
3035
3407
|
this._rowAdded.set({ index: insertedAt, sequence: ++this._changeSequence });
|
|
3036
3408
|
return insertedAt;
|
|
3037
3409
|
}
|
|
@@ -3042,6 +3414,16 @@ class AgridDataSource {
|
|
|
3042
3414
|
*/
|
|
3043
3415
|
removeRow(index) {
|
|
3044
3416
|
this.updateRows(rows => rows.filter((_, i) => i !== index));
|
|
3417
|
+
this._unfilteredAddedRows.update(current => {
|
|
3418
|
+
const next = new Set();
|
|
3419
|
+
for (const addedIndex of current) {
|
|
3420
|
+
if (addedIndex < index)
|
|
3421
|
+
next.add(addedIndex);
|
|
3422
|
+
else if (addedIndex > index)
|
|
3423
|
+
next.add(addedIndex - 1);
|
|
3424
|
+
}
|
|
3425
|
+
return next;
|
|
3426
|
+
});
|
|
3045
3427
|
}
|
|
3046
3428
|
/**
|
|
3047
3429
|
* Move the row at `from` to position `to` (insert-before semantics).
|
|
@@ -3053,12 +3435,30 @@ class AgridDataSource {
|
|
|
3053
3435
|
moveRow(from, to) {
|
|
3054
3436
|
if (from === to)
|
|
3055
3437
|
return;
|
|
3438
|
+
let insertedAt = from;
|
|
3056
3439
|
this.updateRows(rows => {
|
|
3057
3440
|
const arr = [...rows];
|
|
3058
3441
|
const [item] = arr.splice(from, 1);
|
|
3059
|
-
|
|
3442
|
+
insertedAt = to > from ? to - 1 : to;
|
|
3443
|
+
arr.splice(insertedAt, 0, item);
|
|
3060
3444
|
return arr;
|
|
3061
3445
|
});
|
|
3446
|
+
this._unfilteredAddedRows.update(current => {
|
|
3447
|
+
const next = new Set();
|
|
3448
|
+
for (const index of current) {
|
|
3449
|
+
if (index === from) {
|
|
3450
|
+
next.add(insertedAt);
|
|
3451
|
+
continue;
|
|
3452
|
+
}
|
|
3453
|
+
let moved = index;
|
|
3454
|
+
if (moved > from)
|
|
3455
|
+
moved -= 1;
|
|
3456
|
+
if (moved >= insertedAt)
|
|
3457
|
+
moved += 1;
|
|
3458
|
+
next.add(moved);
|
|
3459
|
+
}
|
|
3460
|
+
return next;
|
|
3461
|
+
});
|
|
3062
3462
|
}
|
|
3063
3463
|
/** Return the current row at `index` (non-reactive snapshot). */
|
|
3064
3464
|
getRow(index) {
|
|
@@ -3076,6 +3476,10 @@ class AgridDataSource {
|
|
|
3076
3476
|
this._writableLinkedRows?.set(rows);
|
|
3077
3477
|
this._rows.set(rows);
|
|
3078
3478
|
}
|
|
3479
|
+
/** @internal Clears the transient filter bypass applied to newly inserted rows. */
|
|
3480
|
+
ɵreapplyFiltersToAddedRows() {
|
|
3481
|
+
this._unfilteredAddedRows.set(new Set());
|
|
3482
|
+
}
|
|
3079
3483
|
}
|
|
3080
3484
|
|
|
3081
3485
|
/**
|
|
@@ -3138,7 +3542,8 @@ class AgridDragHandler {
|
|
|
3138
3542
|
const idx = this.reorderOriginalIndex();
|
|
3139
3543
|
if (idx === null)
|
|
3140
3544
|
return '';
|
|
3141
|
-
|
|
3545
|
+
const row = this.opts.dataSource().rows()[idx];
|
|
3546
|
+
return getDisplayForField(col, row?.[col.field], this.opts.locale(), row);
|
|
3142
3547
|
}
|
|
3143
3548
|
_reorderMove = (e) => {
|
|
3144
3549
|
if (this._overlayEl) {
|
|
@@ -3283,7 +3688,7 @@ class AgridDetailController {
|
|
|
3283
3688
|
/** Formatted value shown while a configured detail field is not being edited. */
|
|
3284
3689
|
detailFieldDisplay(item) {
|
|
3285
3690
|
const col = this.opts.detailColumn();
|
|
3286
|
-
return col ? getDisplayForField(col, item.row[col.field], this.opts.locale()) : '';
|
|
3691
|
+
return col ? getDisplayForField(col, item.row[col.field], this.opts.locale(), item.row) : '';
|
|
3287
3692
|
}
|
|
3288
3693
|
/** Whether the configured detail field can be edited for this row. */
|
|
3289
3694
|
isDetailFieldEditable(item) {
|
|
@@ -3590,21 +3995,24 @@ class AgridEditController {
|
|
|
3590
3995
|
return false;
|
|
3591
3996
|
const row = this.opts.dataSource().getRow(rowIndex);
|
|
3592
3997
|
const oldValue = row[col.field];
|
|
3593
|
-
|
|
3998
|
+
const storedValue = col.type === 'number'
|
|
3999
|
+
? coerceNumberInputValue(newValue)
|
|
4000
|
+
: newValue;
|
|
4001
|
+
if (oldValue === storedValue)
|
|
3594
4002
|
return true;
|
|
3595
|
-
const message = col.validate?.(
|
|
4003
|
+
const message = col.validate?.(storedValue, row) ?? null;
|
|
3596
4004
|
if (message) {
|
|
3597
4005
|
this.validationError.set({ rowIndex, colIndex, field: col.field, message });
|
|
3598
|
-
this.opts.onValidationFailed({ rowIndex, field: col.field, value:
|
|
4006
|
+
this.opts.onValidationFailed({ rowIndex, field: col.field, value: storedValue, message });
|
|
3599
4007
|
return false;
|
|
3600
4008
|
}
|
|
3601
|
-
this.opts.dataSource().patchRow(rowIndex, { [col.field]:
|
|
3602
|
-
this.opts.control()?.pushEdit({ rowIndex, field: col.field, oldValue, newValue });
|
|
4009
|
+
this.opts.dataSource().patchRow(rowIndex, { [col.field]: storedValue });
|
|
4010
|
+
this.opts.control()?.pushEdit({ rowIndex, field: col.field, oldValue, newValue: storedValue });
|
|
3603
4011
|
this.opts.onCellEdit({
|
|
3604
4012
|
position: { rowIndex, colIndex },
|
|
3605
4013
|
field: col.field,
|
|
3606
4014
|
oldValue,
|
|
3607
|
-
newValue,
|
|
4015
|
+
newValue: storedValue,
|
|
3608
4016
|
});
|
|
3609
4017
|
this.validationError.set(null);
|
|
3610
4018
|
return true;
|
|
@@ -3679,7 +4087,7 @@ class AgridFindController {
|
|
|
3679
4087
|
return;
|
|
3680
4088
|
for (let colIndex = 0; colIndex < cols.length; colIndex++) {
|
|
3681
4089
|
const col = cols[colIndex];
|
|
3682
|
-
const value = getDisplayForField(col, row[col.field], this.opts.locale()).toLowerCase();
|
|
4090
|
+
const value = getDisplayForField(col, row[col.field], this.opts.locale(), row).toLowerCase();
|
|
3683
4091
|
if (value.includes(query)) {
|
|
3684
4092
|
matches.push({ rowIndex, colIndex });
|
|
3685
4093
|
}
|
|
@@ -4640,7 +5048,7 @@ class AgridPresentationService {
|
|
|
4640
5048
|
const locale = this.opts.locale();
|
|
4641
5049
|
const body = rows
|
|
4642
5050
|
.map(row => cols
|
|
4643
|
-
.map(col => escape(getDisplayForField(col, row[col.field], locale)))
|
|
5051
|
+
.map(col => escape(getDisplayForField(col, row[col.field], locale, row)))
|
|
4644
5052
|
.join(','))
|
|
4645
5053
|
.join('\n');
|
|
4646
5054
|
this.browser.downloadText(filename, `${header}\n${body}`, 'text/csv;charset=utf-8;');
|
|
@@ -4662,7 +5070,7 @@ class AgridPresentationService {
|
|
|
4662
5070
|
return {
|
|
4663
5071
|
name,
|
|
4664
5072
|
header: cols.map(col => col.header),
|
|
4665
|
-
rows: rows.map(row => ({ cells: cols.map(col => this.toXlsxCell(col, row[col.field], locale)) })),
|
|
5073
|
+
rows: rows.map(row => ({ cells: cols.map(col => this.toXlsxCell(col, row[col.field], locale, row)) })),
|
|
4666
5074
|
};
|
|
4667
5075
|
}
|
|
4668
5076
|
buildGroupedSheet(name, cols, groups, locale) {
|
|
@@ -4681,7 +5089,7 @@ class AgridPresentationService {
|
|
|
4681
5089
|
});
|
|
4682
5090
|
rows.push({ cells: summary, level: 0, emphasized: true });
|
|
4683
5091
|
for (const row of group.rows) {
|
|
4684
|
-
rows.push({ cells: cols.map(col => this.toXlsxCell(col, row[col.field], locale)), level: 1 });
|
|
5092
|
+
rows.push({ cells: cols.map(col => this.toXlsxCell(col, row[col.field], locale, row)), level: 1 });
|
|
4685
5093
|
}
|
|
4686
5094
|
}
|
|
4687
5095
|
return { name, header: cols.map(col => col.header), rows, outline: true };
|
|
@@ -4690,11 +5098,12 @@ class AgridPresentationService {
|
|
|
4690
5098
|
* Maps a raw cell value to a typed spreadsheet cell so Excel keeps numbers and dates native
|
|
4691
5099
|
* (sortable, summable). Mapped value lists and custom formatters fall back to display text.
|
|
4692
5100
|
*/
|
|
4693
|
-
toXlsxCell(col, raw, locale) {
|
|
5101
|
+
toXlsxCell(col, raw, locale, row) {
|
|
4694
5102
|
if (raw == null || raw === '')
|
|
4695
5103
|
return { kind: 'empty' };
|
|
4696
|
-
if (col.values?.length)
|
|
4697
|
-
return { kind: 'string', value: getDisplayForField(col, raw, locale) };
|
|
5104
|
+
if (col.values?.length || col.formula) {
|
|
5105
|
+
return { kind: 'string', value: getDisplayForField(col, raw, locale, row) };
|
|
5106
|
+
}
|
|
4698
5107
|
if (col.type === 'number' && typeof raw === 'number' && Number.isFinite(raw)) {
|
|
4699
5108
|
return { kind: 'number', value: raw };
|
|
4700
5109
|
}
|
|
@@ -4705,7 +5114,7 @@ class AgridPresentationService {
|
|
|
4705
5114
|
if (!Number.isNaN(date.getTime()))
|
|
4706
5115
|
return { kind: 'date', value: date };
|
|
4707
5116
|
}
|
|
4708
|
-
return { kind: 'string', value: getDisplayForField(col, raw, locale) };
|
|
5117
|
+
return { kind: 'string', value: getDisplayForField(col, raw, locale, row) };
|
|
4709
5118
|
}
|
|
4710
5119
|
}
|
|
4711
5120
|
|
|
@@ -4930,6 +5339,8 @@ class AgridControl {
|
|
|
4930
5339
|
_loading = signal(false, ...(ngDevMode ? [{ debugName: "_loading" }] : /* istanbul ignore next */ []));
|
|
4931
5340
|
_readonly = signal(false, ...(ngDevMode ? [{ debugName: "_readonly" }] : /* istanbul ignore next */ []));
|
|
4932
5341
|
_autoAddRows = signal(false, ...(ngDevMode ? [{ debugName: "_autoAddRows" }] : /* istanbul ignore next */ []));
|
|
5342
|
+
_filterReapplyRevision = signal(0, ...(ngDevMode ? [{ debugName: "_filterReapplyRevision" }] : /* istanbul ignore next */ []));
|
|
5343
|
+
_filterReapplyNeeded = signal(false, ...(ngDevMode ? [{ debugName: "_filterReapplyNeeded" }] : /* istanbul ignore next */ []));
|
|
4933
5344
|
_rowIndications = signal(new Map(), ...(ngDevMode ? [{ debugName: "_rowIndications" }] : /* istanbul ignore next */ []));
|
|
4934
5345
|
_changedCells = signal(new Set(), ...(ngDevMode ? [{ debugName: "_changedCells" }] : /* istanbul ignore next */ []));
|
|
4935
5346
|
rowIndicationTimers = new Map();
|
|
@@ -5048,6 +5459,25 @@ class AgridControl {
|
|
|
5048
5459
|
setAutoAddRows(value) {
|
|
5049
5460
|
this._autoAddRows.set(value);
|
|
5050
5461
|
}
|
|
5462
|
+
/**
|
|
5463
|
+
* Reapply active filters to rows that were inserted while filters were already active.
|
|
5464
|
+
* By default, newly inserted rows stay visible until this method is called.
|
|
5465
|
+
*/
|
|
5466
|
+
reapplyFilters() {
|
|
5467
|
+
this._filterReapplyNeeded.set(false);
|
|
5468
|
+
this._filterReapplyRevision.update(revision => revision + 1);
|
|
5469
|
+
}
|
|
5470
|
+
/**
|
|
5471
|
+
* `true` when inserted rows are currently bypassing active filters or sorts.
|
|
5472
|
+
* Bind this to visual feedback for a "Reapply filters" action.
|
|
5473
|
+
*/
|
|
5474
|
+
filterReapplyNeeded = this._filterReapplyNeeded.asReadonly();
|
|
5475
|
+
/** @internal Updates {@link filterReapplyNeeded} from the rendered grid projection. */
|
|
5476
|
+
ɵsetFilterReapplyNeeded(value) {
|
|
5477
|
+
this._filterReapplyNeeded.set(value);
|
|
5478
|
+
}
|
|
5479
|
+
/** @internal Emits whenever {@link reapplyFilters} is called. */
|
|
5480
|
+
ɵfilterReapplyRevision = this._filterReapplyRevision.asReadonly();
|
|
5051
5481
|
/**
|
|
5052
5482
|
* When `true`, the control column shows a drag handle and rows can be
|
|
5053
5483
|
* reordered by dragging. Requires `showControlColumn` to be enabled on the grid.
|
|
@@ -5331,6 +5761,44 @@ class AgridControl {
|
|
|
5331
5761
|
getFilter(field) {
|
|
5332
5762
|
return this._filters()[field] ?? { text: '', selectedValues: null, sort: null };
|
|
5333
5763
|
}
|
|
5764
|
+
/** Replace the complete filter/sort state for one field. */
|
|
5765
|
+
setFilter(field, filter) {
|
|
5766
|
+
const nextFilter = this.cloneFilters({ [field]: filter })[field];
|
|
5767
|
+
this._filters.update(filters => ({
|
|
5768
|
+
...filters,
|
|
5769
|
+
[field]: nextFilter,
|
|
5770
|
+
}));
|
|
5771
|
+
this._sortOrder.update(order => {
|
|
5772
|
+
const withoutField = order.filter(item => item !== field);
|
|
5773
|
+
return nextFilter.sort ? [...withoutField, field] : withoutField;
|
|
5774
|
+
});
|
|
5775
|
+
}
|
|
5776
|
+
/** Return a detached JSON-safe snapshot of active column filters, quick filter, and sort order. */
|
|
5777
|
+
getFilterModel() {
|
|
5778
|
+
return {
|
|
5779
|
+
filters: this.cloneFilters(this._filters()),
|
|
5780
|
+
quickFilter: this._quickFilter() || undefined,
|
|
5781
|
+
sortOrder: [...this._sortOrder()],
|
|
5782
|
+
};
|
|
5783
|
+
}
|
|
5784
|
+
/**
|
|
5785
|
+
* Replace active column filters, quick filter, and sort order from a filter model.
|
|
5786
|
+
* Pass `null` to clear all filters and sorts.
|
|
5787
|
+
*/
|
|
5788
|
+
setFilterModel(model) {
|
|
5789
|
+
if (!model) {
|
|
5790
|
+
this.clearAllFilters();
|
|
5791
|
+
return;
|
|
5792
|
+
}
|
|
5793
|
+
const filters = this.cloneFilters(model.filters ?? {});
|
|
5794
|
+
this._filters.set(filters);
|
|
5795
|
+
this._quickFilter.set(model.quickFilter ?? '');
|
|
5796
|
+
const ordered = (model.sortOrder ?? []).filter(field => !!filters[field]?.sort);
|
|
5797
|
+
const missingSortedFields = Object.entries(filters)
|
|
5798
|
+
.filter(([field, filter]) => !!filter.sort && !ordered.includes(field))
|
|
5799
|
+
.map(([field]) => field);
|
|
5800
|
+
this._sortOrder.set([...ordered, ...missingSortedFields]);
|
|
5801
|
+
}
|
|
5334
5802
|
/**
|
|
5335
5803
|
* Set the free-text filter for a column.
|
|
5336
5804
|
* An empty string removes the text filter for that column.
|
|
@@ -5475,6 +5943,15 @@ class AgridControl {
|
|
|
5475
5943
|
static fromJSON(state) {
|
|
5476
5944
|
return new AgridControl(state);
|
|
5477
5945
|
}
|
|
5946
|
+
cloneFilters(filters) {
|
|
5947
|
+
return Object.fromEntries(Object.entries(filters).map(([field, filter]) => [
|
|
5948
|
+
field,
|
|
5949
|
+
{
|
|
5950
|
+
...filter,
|
|
5951
|
+
selectedValues: filter.selectedValues ? [...filter.selectedValues] : filter.selectedValues,
|
|
5952
|
+
},
|
|
5953
|
+
]));
|
|
5954
|
+
}
|
|
5478
5955
|
}
|
|
5479
5956
|
/** @internal Bridge for deprecated writable signals on AgridProvider. */
|
|
5480
5957
|
function ɵgetAgridControlRuntimeState(control) {
|
|
@@ -5510,12 +5987,19 @@ class AgridProvider {
|
|
|
5510
5987
|
_localizations = new Map();
|
|
5511
5988
|
exportBridge = null;
|
|
5512
5989
|
_visibleRows = signal(null, ...(ngDevMode ? [{ debugName: "_visibleRows" }] : /* istanbul ignore next */ []));
|
|
5990
|
+
_serverQuery = signal(null, ...(ngDevMode ? [{ debugName: "_serverQuery" }] : /* istanbul ignore next */ []));
|
|
5513
5991
|
/**
|
|
5514
5992
|
* The grid's currently filtered and sorted rows, as published by the rendered grid component.
|
|
5515
5993
|
* Falls back to every datasource row when no grid is attached. Link a chart to this signal to
|
|
5516
5994
|
* keep it in sync with the grid's filters and sorting.
|
|
5517
5995
|
*/
|
|
5518
5996
|
visibleRows = computed(() => this._visibleRows() ?? this.datasource.rows(), ...(ngDevMode ? [{ debugName: "visibleRows" }] : /* istanbul ignore next */ []));
|
|
5997
|
+
/**
|
|
5998
|
+
* Complete server-side filter/sort/page query published by the rendered grid.
|
|
5999
|
+
* Useful for signal-backed stores that fetch data from an API. `null` means the grid is not in
|
|
6000
|
+
* server-side filtering or pagination mode.
|
|
6001
|
+
*/
|
|
6002
|
+
serverQuery = this._serverQuery.asReadonly();
|
|
5519
6003
|
/**
|
|
5520
6004
|
* @internal Published by the rendered grid whenever its filtered/sorted projection changes.
|
|
5521
6005
|
* Pass `null` on teardown so {@link visibleRows} falls back to the raw datasource. The grid works
|
|
@@ -5524,6 +6008,10 @@ class AgridProvider {
|
|
|
5524
6008
|
ɵsetVisibleRows(rows) {
|
|
5525
6009
|
this._visibleRows.set(rows);
|
|
5526
6010
|
}
|
|
6011
|
+
/** @internal Published by the rendered grid whenever the server-side query state changes. */
|
|
6012
|
+
ɵsetServerQuery(query) {
|
|
6013
|
+
this._serverQuery.set(query);
|
|
6014
|
+
}
|
|
5527
6015
|
/** Read-only view of registered per-locale text overrides. Used by the grid to resolve locale text. */
|
|
5528
6016
|
get localizations() {
|
|
5529
6017
|
return this._localizations;
|
|
@@ -5550,6 +6038,8 @@ class AgridProvider {
|
|
|
5550
6038
|
allowAddRows;
|
|
5551
6039
|
/** Whether the control column is rendered. */
|
|
5552
6040
|
showControlColumn;
|
|
6041
|
+
/** Whether the control column displays automatic row numbers. */
|
|
6042
|
+
showRowNumbers;
|
|
5553
6043
|
/** Whether rows can be marked for inclusion in clipboard copies. */
|
|
5554
6044
|
enableRowMarking;
|
|
5555
6045
|
/** Whether complete columns can be marked from their headers. */
|
|
@@ -5564,6 +6054,8 @@ class AgridProvider {
|
|
|
5564
6054
|
filterDebounceMs;
|
|
5565
6055
|
/** Whether the global quick-filter box is shown above the grid. */
|
|
5566
6056
|
enableQuickFilter;
|
|
6057
|
+
/** Whether the formula/input bar is shown above the grid body. */
|
|
6058
|
+
showFormulaBar;
|
|
5567
6059
|
/** Commands rendered in the optional menu bar above the column headers. */
|
|
5568
6060
|
menuBarItems;
|
|
5569
6061
|
/** Enabled sorting mode. */
|
|
@@ -5594,6 +6086,8 @@ class AgridProvider {
|
|
|
5594
6086
|
useSidebarEditor;
|
|
5595
6087
|
/** Optional callback returning CSS classes for a whole data row. */
|
|
5596
6088
|
getRowClass;
|
|
6089
|
+
/** Optional application-owned row predicate applied by the client-side projection. */
|
|
6090
|
+
externalFilter;
|
|
5597
6091
|
/** Optional callback designating rows pinned to the top or bottom of the body. */
|
|
5598
6092
|
pinRow;
|
|
5599
6093
|
/** Whether master/detail expandable detail rows are enabled. */
|
|
@@ -5641,6 +6135,7 @@ class AgridProvider {
|
|
|
5641
6135
|
this.control.setAutoAddRows(config.autoAddRows);
|
|
5642
6136
|
this.autoAddRows = runtimeState.autoAddRows;
|
|
5643
6137
|
this.showControlColumn = config.showControlColumn ?? false;
|
|
6138
|
+
this.showRowNumbers = config.showRowNumbers ?? false;
|
|
5644
6139
|
this.enableRowMarking = config.enableRowMarking ?? false;
|
|
5645
6140
|
this.enableColumnMarking = config.enableColumnMarking ?? false;
|
|
5646
6141
|
this.showSidebar = config.showSidebar ?? false;
|
|
@@ -5648,6 +6143,7 @@ class AgridProvider {
|
|
|
5648
6143
|
this.serverSideFiltering = this.serverSideRowModel ? true : config.serverSideFiltering ?? false;
|
|
5649
6144
|
this.filterDebounceMs = Math.max(0, config.filterDebounceMs ?? 300);
|
|
5650
6145
|
this.enableQuickFilter = config.enableQuickFilter ?? false;
|
|
6146
|
+
this.showFormulaBar = config.showFormulaBar ?? false;
|
|
5651
6147
|
this.menuBarItems = config.menuBarItems ?? [];
|
|
5652
6148
|
this.sortOption = config.sortOption ?? 'multi';
|
|
5653
6149
|
this.rowSelection = config.rowSelection ?? 'none';
|
|
@@ -5668,6 +6164,7 @@ class AgridProvider {
|
|
|
5668
6164
|
this.readonlyGrid = runtimeState.readonly;
|
|
5669
6165
|
this.useSidebarEditor = config.useSidebarEditor ?? false;
|
|
5670
6166
|
this.getRowClass = config.getRowClass;
|
|
6167
|
+
this.externalFilter = config.externalFilter;
|
|
5671
6168
|
this.pinRow = config.pinRow;
|
|
5672
6169
|
this.masterDetail = config.masterDetail ?? false;
|
|
5673
6170
|
this.detailRenderer = config.detailRenderer;
|
|
@@ -5872,6 +6369,7 @@ class AgridServerSideRowModel extends AgridDataSource {
|
|
|
5872
6369
|
slots = [];
|
|
5873
6370
|
loadedBlocks = new Map();
|
|
5874
6371
|
loadingBlocks = new Set();
|
|
6372
|
+
failedBlocks = new Set();
|
|
5875
6373
|
query = { filters: {}, sort: [], quickFilter: '' };
|
|
5876
6374
|
queryKey = '';
|
|
5877
6375
|
generation = 0;
|
|
@@ -5911,9 +6409,39 @@ class AgridServerSideRowModel extends AgridDataSource {
|
|
|
5911
6409
|
this.reset();
|
|
5912
6410
|
return true;
|
|
5913
6411
|
}
|
|
5914
|
-
/** Invalidate
|
|
5915
|
-
refresh() {
|
|
5916
|
-
|
|
6412
|
+
/** Invalidate cached blocks while preserving the current query and known total row count. */
|
|
6413
|
+
refresh(options = {}) {
|
|
6414
|
+
const purge = options.purge ?? true;
|
|
6415
|
+
this.generation++;
|
|
6416
|
+
this.loadingBlocks.clear();
|
|
6417
|
+
this.failedBlocks.clear();
|
|
6418
|
+
this._loading.set(false);
|
|
6419
|
+
this._error.set(null);
|
|
6420
|
+
if (purge) {
|
|
6421
|
+
this.loadedBlocks.clear();
|
|
6422
|
+
const length = this.knownRowCount ? this._rowCount() : this.blockSize;
|
|
6423
|
+
this.replaceSlots(this.createPlaceholders(length));
|
|
6424
|
+
}
|
|
6425
|
+
else {
|
|
6426
|
+
this.loadedBlocks.clear();
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6429
|
+
/** Clear the block cache and show placeholders until requested blocks are reloaded. */
|
|
6430
|
+
purgeCache() {
|
|
6431
|
+
this.refresh({ purge: true });
|
|
6432
|
+
}
|
|
6433
|
+
/** Retry the most recently failed block, or a specific block index when supplied. */
|
|
6434
|
+
retryFailedBlock(block) {
|
|
6435
|
+
const target = block ?? [...this.failedBlocks].at(-1);
|
|
6436
|
+
if (target === undefined)
|
|
6437
|
+
return;
|
|
6438
|
+
this.failedBlocks.delete(target);
|
|
6439
|
+
this.loadedBlocks.delete(target);
|
|
6440
|
+
void this.loadBlock(target);
|
|
6441
|
+
}
|
|
6442
|
+
/** Failed block indices that can be passed to {@link retryFailedBlock}. */
|
|
6443
|
+
failedBlockIndices() {
|
|
6444
|
+
return [...this.failedBlocks].sort((left, right) => left - right);
|
|
5917
6445
|
}
|
|
5918
6446
|
/** Ensure every block intersecting the requested half-open range is loaded. */
|
|
5919
6447
|
ensureRange(startRow, endRow) {
|
|
@@ -5935,6 +6463,7 @@ class AgridServerSideRowModel extends AgridDataSource {
|
|
|
5935
6463
|
this.generation++;
|
|
5936
6464
|
this.loadedBlocks.clear();
|
|
5937
6465
|
this.loadingBlocks.clear();
|
|
6466
|
+
this.failedBlocks.clear();
|
|
5938
6467
|
this._loading.set(false);
|
|
5939
6468
|
this._error.set(null);
|
|
5940
6469
|
const length = this.knownRowCount ? this._rowCount() : this.blockSize;
|
|
@@ -5964,11 +6493,14 @@ class AgridServerSideRowModel extends AgridDataSource {
|
|
|
5964
6493
|
if (generation !== this.generation)
|
|
5965
6494
|
return;
|
|
5966
6495
|
this.applyBlock(block, startRow, result);
|
|
6496
|
+
this.failedBlocks.delete(block);
|
|
5967
6497
|
this._error.set(null);
|
|
5968
6498
|
}
|
|
5969
6499
|
catch (error) {
|
|
5970
|
-
if (generation === this.generation)
|
|
6500
|
+
if (generation === this.generation) {
|
|
6501
|
+
this.failedBlocks.add(block);
|
|
5971
6502
|
this._error.set(error);
|
|
6503
|
+
}
|
|
5972
6504
|
}
|
|
5973
6505
|
finally {
|
|
5974
6506
|
if (generation === this.generation) {
|
|
@@ -6065,17 +6597,33 @@ class AgridProjectionModel {
|
|
|
6065
6597
|
if (!control || this.opts.serverSideFiltering())
|
|
6066
6598
|
return indices;
|
|
6067
6599
|
const filters = control.filters();
|
|
6600
|
+
const hasRowFilter = this.hasActiveRowFilter(filters, control.quickFilter());
|
|
6068
6601
|
indices = applyTextAndValueFilters(rows, indices, filters, colMap, this.opts.locale());
|
|
6069
6602
|
const quick = control.quickFilter();
|
|
6070
6603
|
if (quick) {
|
|
6071
6604
|
indices = applyQuickFilter(rows, indices, quick, this.opts.visibleColDefs(), this.opts.locale());
|
|
6072
6605
|
}
|
|
6606
|
+
const externalFilter = this.opts.externalFilter?.();
|
|
6607
|
+
if (externalFilter) {
|
|
6608
|
+
indices = indices.filter(index => externalFilter({ row: rows[index], index }));
|
|
6609
|
+
}
|
|
6610
|
+
if (hasRowFilter)
|
|
6611
|
+
indices = this.includeUnfilteredAddedRows(indices, rows.length);
|
|
6073
6612
|
if (control.groupByField() && !this.opts.pivotMode?.())
|
|
6074
6613
|
return indices;
|
|
6075
6614
|
const sortEntries = this.sortEntries(filters);
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6615
|
+
if (!sortEntries.length)
|
|
6616
|
+
return indices;
|
|
6617
|
+
const addedRows = this.opts.dataSource().ɵunfilteredAddedRows();
|
|
6618
|
+
if (addedRows.size === 0) {
|
|
6619
|
+
return applySortToIndices(rows, indices, sortEntries, colMap, this.opts.locale());
|
|
6620
|
+
}
|
|
6621
|
+
const added = indices.filter(index => addedRows.has(index));
|
|
6622
|
+
const regular = indices.filter(index => !addedRows.has(index));
|
|
6623
|
+
return [
|
|
6624
|
+
...applySortToIndices(rows, regular, sortEntries, colMap, this.opts.locale()),
|
|
6625
|
+
...added,
|
|
6626
|
+
];
|
|
6079
6627
|
}, ...(ngDevMode ? [{ debugName: "filteredSortedIndices" }] : /* istanbul ignore next */ []));
|
|
6080
6628
|
/** Total filtered row count, unaffected by client-side pagination. */
|
|
6081
6629
|
filteredRowCount = computed(() => this.filteredSortedIndices().length, ...(ngDevMode ? [{ debugName: "filteredRowCount" }] : /* istanbul ignore next */ []));
|
|
@@ -6280,6 +6828,25 @@ class AgridProjectionModel {
|
|
|
6280
6828
|
.map(field => [field, filters[field]])
|
|
6281
6829
|
.filter(([, filter]) => !!filter?.sort);
|
|
6282
6830
|
}
|
|
6831
|
+
hasActiveRowFilter(filters, quickFilter) {
|
|
6832
|
+
return !!quickFilter || Object.values(filters).some(filter => !!filter.text
|
|
6833
|
+
|| filter.selectedValues !== null
|
|
6834
|
+
|| (!!filter.operator && filter.operand != null && filter.operand !== ''));
|
|
6835
|
+
}
|
|
6836
|
+
includeUnfilteredAddedRows(indices, rowCount) {
|
|
6837
|
+
const addedRows = this.opts.dataSource().ɵunfilteredAddedRows();
|
|
6838
|
+
if (addedRows.size === 0)
|
|
6839
|
+
return indices;
|
|
6840
|
+
const visible = new Set(indices);
|
|
6841
|
+
const next = [...indices];
|
|
6842
|
+
for (const index of addedRows) {
|
|
6843
|
+
if (index >= 0 && index < rowCount && !visible.has(index)) {
|
|
6844
|
+
visible.add(index);
|
|
6845
|
+
next.push(index);
|
|
6846
|
+
}
|
|
6847
|
+
}
|
|
6848
|
+
return next;
|
|
6849
|
+
}
|
|
6283
6850
|
appendTreeDetailItems(items, rows, treeConfig) {
|
|
6284
6851
|
const expandedDetail = this.opts.masterDetail?.() ? this.opts.expandedDetailIds?.() : null;
|
|
6285
6852
|
if (!expandedDetail?.size)
|
|
@@ -6821,7 +7388,7 @@ class AgridRowController {
|
|
|
6821
7388
|
copyCellToClipboard(originalIndex, col) {
|
|
6822
7389
|
const rows = this.opts.dataSource().rows();
|
|
6823
7390
|
const text = this.copyIndices(originalIndex)
|
|
6824
|
-
.map(index => getDisplayForField(col, rows[index]?.[col.field], this.opts.locale()))
|
|
7391
|
+
.map(index => getDisplayForField(col, rows[index]?.[col.field], this.opts.locale(), rows[index]))
|
|
6825
7392
|
.join('\n');
|
|
6826
7393
|
void this.browser.writeClipboard(text);
|
|
6827
7394
|
this.closeCellContextMenu();
|
|
@@ -6832,7 +7399,7 @@ class AgridRowController {
|
|
|
6832
7399
|
const cols = this.opts.visibleColDefs();
|
|
6833
7400
|
const text = this.copyIndices(originalIndex)
|
|
6834
7401
|
.map(index => cols
|
|
6835
|
-
.map(col => getDisplayForField(col, rows[index]?.[col.field], this.opts.locale()))
|
|
7402
|
+
.map(col => getDisplayForField(col, rows[index]?.[col.field], this.opts.locale(), rows[index]))
|
|
6836
7403
|
.join('\t'))
|
|
6837
7404
|
.join('\n');
|
|
6838
7405
|
void this.browser.writeClipboard(text);
|
|
@@ -7183,7 +7750,7 @@ class AgridSidebarComponent {
|
|
|
7183
7750
|
}
|
|
7184
7751
|
return {
|
|
7185
7752
|
label: col.header,
|
|
7186
|
-
value: getDisplayForField(col, rawValue, locale),
|
|
7753
|
+
value: getDisplayForField(col, rawValue, locale, row),
|
|
7187
7754
|
rawValue,
|
|
7188
7755
|
inputValue,
|
|
7189
7756
|
hidden: hiddenColumns.has(col.field),
|
|
@@ -7343,7 +7910,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
7343
7910
|
}], propDecorators: { itemSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "agridVariableRowSize", required: false }] }] } });
|
|
7344
7911
|
|
|
7345
7912
|
/**
|
|
7346
|
-
* Excel-like data grid for Angular 21.
|
|
7913
|
+
* Excel-like data grid for Angular 21 and 22.
|
|
7347
7914
|
*
|
|
7348
7915
|
* ## Minimal setup
|
|
7349
7916
|
* ```html
|
|
@@ -7378,13 +7945,23 @@ class AgridComponent {
|
|
|
7378
7945
|
autoAddRows = computed(() => !this.provider().pivotConfig && (this.control()?.autoAddRows() ?? false), ...(ngDevMode ? [{ debugName: "autoAddRows" }] : /* istanbul ignore next */ []));
|
|
7379
7946
|
enableRowMarking = computed(() => this.provider().enableRowMarking, ...(ngDevMode ? [{ debugName: "enableRowMarking" }] : /* istanbul ignore next */ []));
|
|
7380
7947
|
enableColumnMarking = computed(() => this.provider().enableColumnMarking, ...(ngDevMode ? [{ debugName: "enableColumnMarking" }] : /* istanbul ignore next */ []));
|
|
7381
|
-
|
|
7382
|
-
|
|
7948
|
+
showRowNumbers = computed(() => this.provider().showRowNumbers, ...(ngDevMode ? [{ debugName: "showRowNumbers" }] : /* istanbul ignore next */ []));
|
|
7949
|
+
showControlColumn = computed(() => this.provider().showControlColumn
|
|
7950
|
+
|| this.showRowNumbers()
|
|
7951
|
+
|| this.enableRowMarking()
|
|
7952
|
+
|| this.masterDetail(), ...(ngDevMode ? [{ debugName: "showControlColumn" }] : /* istanbul ignore next */ []));
|
|
7953
|
+
controlColumnWidth = computed(() => {
|
|
7954
|
+
if (!this.showRowNumbers())
|
|
7955
|
+
return this.enableRowMarking() ? 48 : 24;
|
|
7956
|
+
const numberWidth = this.rowNumberColumnWidth();
|
|
7957
|
+
return this.enableRowMarking() ? numberWidth + 20 : numberWidth;
|
|
7958
|
+
}, ...(ngDevMode ? [{ debugName: "controlColumnWidth" }] : /* istanbul ignore next */ []));
|
|
7383
7959
|
showSidebar = computed(() => this.provider().showSidebar, ...(ngDevMode ? [{ debugName: "showSidebar" }] : /* istanbul ignore next */ []));
|
|
7384
7960
|
autoOpenDetail = computed(() => this.provider().autoOpenDetail, ...(ngDevMode ? [{ debugName: "autoOpenDetail" }] : /* istanbul ignore next */ []));
|
|
7385
7961
|
serverSideFiltering = computed(() => this.provider().serverSideFiltering, ...(ngDevMode ? [{ debugName: "serverSideFiltering" }] : /* istanbul ignore next */ []));
|
|
7386
7962
|
filterDebounceMs = computed(() => this.provider().filterDebounceMs, ...(ngDevMode ? [{ debugName: "filterDebounceMs" }] : /* istanbul ignore next */ []));
|
|
7387
7963
|
enableQuickFilter = computed(() => this.provider().enableQuickFilter, ...(ngDevMode ? [{ debugName: "enableQuickFilter" }] : /* istanbul ignore next */ []));
|
|
7964
|
+
showFormulaBar = computed(() => this.provider().showFormulaBar, ...(ngDevMode ? [{ debugName: "showFormulaBar" }] : /* istanbul ignore next */ []));
|
|
7388
7965
|
menuBarItems = computed(() => this.provider().menuBarItems, ...(ngDevMode ? [{ debugName: "menuBarItems" }] : /* istanbul ignore next */ []));
|
|
7389
7966
|
quickFilterValue = computed(() => this.control()?.quickFilter() ?? '', ...(ngDevMode ? [{ debugName: "quickFilterValue" }] : /* istanbul ignore next */ []));
|
|
7390
7967
|
sortOption = computed(() => this.provider().sortOption, ...(ngDevMode ? [{ debugName: "sortOption" }] : /* istanbul ignore next */ []));
|
|
@@ -7407,6 +7984,7 @@ class AgridComponent {
|
|
|
7407
7984
|
hideGridStatusBar = computed(() => this.provider().hideGridStatusBar, ...(ngDevMode ? [{ debugName: "hideGridStatusBar" }] : /* istanbul ignore next */ []));
|
|
7408
7985
|
/** Host callback for per-row CSS classes, or `undefined`. */
|
|
7409
7986
|
rowClassFn = computed(() => this.provider().getRowClass, ...(ngDevMode ? [{ debugName: "rowClassFn" }] : /* istanbul ignore next */ []));
|
|
7987
|
+
externalFilterFn = computed(() => this.provider().externalFilter, ...(ngDevMode ? [{ debugName: "externalFilterFn" }] : /* istanbul ignore next */ []));
|
|
7410
7988
|
/** Host callback designating pinned rows, or `undefined`. */
|
|
7411
7989
|
pinRowFn = computed(() => this.provider().pinRow, ...(ngDevMode ? [{ debugName: "pinRowFn" }] : /* istanbul ignore next */ []));
|
|
7412
7990
|
pivotRowColumnField = computed(() => {
|
|
@@ -7550,6 +8128,8 @@ class AgridComponent {
|
|
|
7550
8128
|
filterChange = output();
|
|
7551
8129
|
/** Emitted when a column sort changes in server-side filtering mode. */
|
|
7552
8130
|
sortChange = output();
|
|
8131
|
+
/** Emitted with the complete server-side filter/sort/page query snapshot. */
|
|
8132
|
+
serverQueryChange = output();
|
|
7553
8133
|
/**
|
|
7554
8134
|
* Emitted (debounced) when the global quick-filter text changes in server-side filtering mode.
|
|
7555
8135
|
* The host should refetch rows matching the text. Not emitted in client mode, where the grid
|
|
@@ -7560,6 +8140,8 @@ class AgridComponent {
|
|
|
7560
8140
|
validationFailed = output();
|
|
7561
8141
|
/** Emitted when a column's optional cell information button is clicked. */
|
|
7562
8142
|
cellInfo = output();
|
|
8143
|
+
/** Emitted when the selected cell changes. `null` = cell selection cleared. */
|
|
8144
|
+
cellSelect = output();
|
|
7563
8145
|
/** Emitted for every enabled menu-bar button or dropdown item, carrying its configured id. */
|
|
7564
8146
|
menuBarAction = output();
|
|
7565
8147
|
/** Emitted if there is a Detail pane Action without text property */
|
|
@@ -7567,6 +8149,7 @@ class AgridComponent {
|
|
|
7567
8149
|
// ── Public state ─────────────────────────────────────────────────────────────
|
|
7568
8150
|
/** Currently focused cell, or `null`. */
|
|
7569
8151
|
selectedCell = signal(null, ...(ngDevMode ? [{ debugName: "selectedCell" }] : /* istanbul ignore next */ []));
|
|
8152
|
+
lastEmittedCell = undefined;
|
|
7570
8153
|
/** Original indices of rows whose master/detail panel is currently expanded. */
|
|
7571
8154
|
_expandedDetailIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "_expandedDetailIds" }] : /* istanbul ignore next */ []));
|
|
7572
8155
|
/**
|
|
@@ -7575,9 +8158,13 @@ class AgridComponent {
|
|
|
7575
8158
|
* provider predicate by {@link effectivePinRow}.
|
|
7576
8159
|
*/
|
|
7577
8160
|
_pinnedRows = signal(new Map(), ...(ngDevMode ? [{ debugName: "_pinnedRows" }] : /* istanbul ignore next */ []));
|
|
8161
|
+
formulaBarDraft = signal('', ...(ngDevMode ? [{ debugName: "formulaBarDraft" }] : /* istanbul ignore next */ []));
|
|
8162
|
+
formulaBarFocused = signal(false, ...(ngDevMode ? [{ debugName: "formulaBarFocused" }] : /* istanbul ignore next */ []));
|
|
8163
|
+
formulaBarEditCell = null;
|
|
7578
8164
|
markedIndices = signal(new Set(), ...(ngDevMode ? [{ debugName: "markedIndices" }] : /* istanbul ignore next */ []));
|
|
7579
8165
|
markedFields = signal(new Set(), ...(ngDevMode ? [{ debugName: "markedFields" }] : /* istanbul ignore next */ []));
|
|
7580
8166
|
firstDataRenderedEmitted = false;
|
|
8167
|
+
serverQueryProvider = null;
|
|
7581
8168
|
/** Original datasource indices marked for inclusion in copy operations. */
|
|
7582
8169
|
markedRowIndices = this.markedIndices.asReadonly();
|
|
7583
8170
|
/** Fields currently marked as complete columns. */
|
|
@@ -7596,6 +8183,44 @@ class AgridComponent {
|
|
|
7596
8183
|
get editSeedChar() { return this.editController.editSeedChar; }
|
|
7597
8184
|
/** Whether the active text editor should select all text when it opens. */
|
|
7598
8185
|
get selectTextOnEdit() { return this.editController.selectTextOnEdit; }
|
|
8186
|
+
/** Return the first currently selected row, or `null` when no row is selected. */
|
|
8187
|
+
getCurrentRow() {
|
|
8188
|
+
const originalIndex = this.selectedRowIndex();
|
|
8189
|
+
if (originalIndex === null)
|
|
8190
|
+
return null;
|
|
8191
|
+
const row = this.dataSource().rows()[originalIndex];
|
|
8192
|
+
return row ? { row, originalIndex } : null;
|
|
8193
|
+
}
|
|
8194
|
+
/** Return the currently selected cell with row, field, value, and column metadata. */
|
|
8195
|
+
getCurrentCell() {
|
|
8196
|
+
return this.resolveCurrentCell(this.selectedCell());
|
|
8197
|
+
}
|
|
8198
|
+
formulaBarLabel = computed(() => {
|
|
8199
|
+
const cell = this.selectedCell();
|
|
8200
|
+
const col = cell ? this.visibleColDefs()[cell.colIndex] : null;
|
|
8201
|
+
if (!cell || !col)
|
|
8202
|
+
return '';
|
|
8203
|
+
return `${col.field}${cell.rowIndex + 1}`;
|
|
8204
|
+
}, ...(ngDevMode ? [{ debugName: "formulaBarLabel" }] : /* istanbul ignore next */ []));
|
|
8205
|
+
resolveCurrentCell(position) {
|
|
8206
|
+
if (!position)
|
|
8207
|
+
return null;
|
|
8208
|
+
const row = this.dataSource().rows()[position.rowIndex];
|
|
8209
|
+
const column = this.visibleColDefs()[position.colIndex];
|
|
8210
|
+
if (!row || !column)
|
|
8211
|
+
return null;
|
|
8212
|
+
return {
|
|
8213
|
+
position: { ...position },
|
|
8214
|
+
row,
|
|
8215
|
+
originalIndex: position.rowIndex,
|
|
8216
|
+
field: column.field,
|
|
8217
|
+
value: row[column.field],
|
|
8218
|
+
column,
|
|
8219
|
+
};
|
|
8220
|
+
}
|
|
8221
|
+
sameCell(a, b) {
|
|
8222
|
+
return a?.rowIndex === b?.rowIndex && a?.colIndex === b?.colIndex;
|
|
8223
|
+
}
|
|
7599
8224
|
/** Toggle the sidebar open/closed. */
|
|
7600
8225
|
toggleSidebar() { this.sidebarController.toggle(); }
|
|
7601
8226
|
/** @internal */
|
|
@@ -7816,6 +8441,10 @@ class AgridComponent {
|
|
|
7816
8441
|
pinnedBodyColumns = computed(() => this.buildBodyColumns(this.pinnedColDefs()), ...(ngDevMode ? [{ debugName: "pinnedBodyColumns" }] : /* istanbul ignore next */ []));
|
|
7817
8442
|
scrollableBodyColumns = computed(() => this.buildBodyColumns(this.scrollableColDefs()), ...(ngDevMode ? [{ debugName: "scrollableBodyColumns" }] : /* istanbul ignore next */ []));
|
|
7818
8443
|
rightBodyColumns = computed(() => this.buildBodyColumns(this.rightPinnedColDefs()), ...(ngDevMode ? [{ debugName: "rightBodyColumns" }] : /* istanbul ignore next */ []));
|
|
8444
|
+
/** @internal Whether a pane needs per-cell span resolution. */
|
|
8445
|
+
pinnedPaneHasSpans = computed(() => this.pinnedColDefs().some(col => col.colSpan), ...(ngDevMode ? [{ debugName: "pinnedPaneHasSpans" }] : /* istanbul ignore next */ []));
|
|
8446
|
+
scrollablePaneHasSpans = computed(() => this.scrollableColDefs().some(col => col.colSpan), ...(ngDevMode ? [{ debugName: "scrollablePaneHasSpans" }] : /* istanbul ignore next */ []));
|
|
8447
|
+
rightPaneHasSpans = computed(() => this.rightPinnedColDefs().some(col => col.colSpan), ...(ngDevMode ? [{ debugName: "rightPaneHasSpans" }] : /* istanbul ignore next */ []));
|
|
7819
8448
|
/**
|
|
7820
8449
|
* Resolves the per-column bindings shared by every data, footer, and ghost cell. Reads only
|
|
7821
8450
|
* layout/drag/pinning signals, so the result is reused across all rows and recomputes only
|
|
@@ -7860,6 +8489,7 @@ class AgridComponent {
|
|
|
7860
8489
|
pivotMode: this.pivotMode,
|
|
7861
8490
|
expandedTreeIds: this.treeController.expandedIds,
|
|
7862
8491
|
pinRow: this.effectivePinRow,
|
|
8492
|
+
externalFilter: this.externalFilterFn,
|
|
7863
8493
|
masterDetail: this.masterDetail,
|
|
7864
8494
|
expandedDetailIds: this._expandedDetailIds,
|
|
7865
8495
|
});
|
|
@@ -7958,6 +8588,24 @@ class AgridComponent {
|
|
|
7958
8588
|
}
|
|
7959
8589
|
return map;
|
|
7960
8590
|
}, ...(ngDevMode ? [{ debugName: "dataRowIsOdd" }] : /* istanbul ignore next */ []));
|
|
8591
|
+
/** Maps originalIndex → 1-based filtered/sorted row number for the control column. */
|
|
8592
|
+
rowNumbers = computed(() => {
|
|
8593
|
+
const map = new Map();
|
|
8594
|
+
this.projection.filteredSortedIndices().forEach((originalIndex, index) => {
|
|
8595
|
+
map.set(originalIndex, index + 1);
|
|
8596
|
+
});
|
|
8597
|
+
return map;
|
|
8598
|
+
}, ...(ngDevMode ? [{ debugName: "rowNumbers" }] : /* istanbul ignore next */ []));
|
|
8599
|
+
/** Width needed for the largest currently rendered row number. */
|
|
8600
|
+
rowNumberColumnWidth = computed(() => {
|
|
8601
|
+
const maxNumber = Math.max(1, ...[
|
|
8602
|
+
...this.pinnedTopItems(),
|
|
8603
|
+
...this.filteredItems(),
|
|
8604
|
+
...this.pinnedBottomItems(),
|
|
8605
|
+
].map(item => this.visibleRowNumber(item)).filter(number => number !== null));
|
|
8606
|
+
const digits = String(maxNumber).length;
|
|
8607
|
+
return Math.max(36, 20 + digits * 8);
|
|
8608
|
+
}, ...(ngDevMode ? [{ debugName: "rowNumberColumnWidth" }] : /* istanbul ignore next */ []));
|
|
7961
8609
|
displayItems = computed(() => {
|
|
7962
8610
|
const items = this.filteredItems();
|
|
7963
8611
|
const dragIdx = this.dragHandler.reorderOriginalIndex();
|
|
@@ -8359,6 +9007,8 @@ class AgridComponent {
|
|
|
8359
9007
|
dirtyInlineRows = new Set();
|
|
8360
9008
|
dirtyRowsDataSource = null;
|
|
8361
9009
|
changedCellsDataSource = null;
|
|
9010
|
+
dirtyInlineRowsIdleTimer = null;
|
|
9011
|
+
dirtyInlineRowsIdleFlushMs = 2000;
|
|
8362
9012
|
emitEditEvents(event) {
|
|
8363
9013
|
this.cellEdit.emit(event);
|
|
8364
9014
|
this.emitRecordEdit(event.position.rowIndex);
|
|
@@ -8381,6 +9031,7 @@ class AgridComponent {
|
|
|
8381
9031
|
this.dirtyRowsDataSource = datasource;
|
|
8382
9032
|
}
|
|
8383
9033
|
this.dirtyInlineRows.add(index);
|
|
9034
|
+
this.scheduleDirtyInlineRowsIdleFlush();
|
|
8384
9035
|
}
|
|
8385
9036
|
markCellChanged(event) {
|
|
8386
9037
|
if (!this.showChangedCellIndicator())
|
|
@@ -8397,6 +9048,7 @@ class AgridComponent {
|
|
|
8397
9048
|
if (this.dirtyRowsDataSource !== datasource) {
|
|
8398
9049
|
this.dirtyInlineRows.clear();
|
|
8399
9050
|
this.dirtyRowsDataSource = datasource;
|
|
9051
|
+
this.clearDirtyInlineRowsIdleFlush();
|
|
8400
9052
|
return;
|
|
8401
9053
|
}
|
|
8402
9054
|
for (const index of [...this.dirtyInlineRows].sort((a, b) => a - b)) {
|
|
@@ -8406,6 +9058,29 @@ class AgridComponent {
|
|
|
8406
9058
|
if (index >= 0 && index < datasource.length)
|
|
8407
9059
|
this.emitRowChanged(index);
|
|
8408
9060
|
}
|
|
9061
|
+
if (this.dirtyInlineRows.size === 0)
|
|
9062
|
+
this.clearDirtyInlineRowsIdleFlush();
|
|
9063
|
+
else
|
|
9064
|
+
this.scheduleDirtyInlineRowsIdleFlush();
|
|
9065
|
+
}
|
|
9066
|
+
scheduleDirtyInlineRowsIdleFlush() {
|
|
9067
|
+
this.clearDirtyInlineRowsIdleFlush();
|
|
9068
|
+
if (this.dirtyInlineRows.size === 0)
|
|
9069
|
+
return;
|
|
9070
|
+
this.dirtyInlineRowsIdleTimer = setTimeout(() => {
|
|
9071
|
+
this.dirtyInlineRowsIdleTimer = null;
|
|
9072
|
+
if (this.editingCell()) {
|
|
9073
|
+
this.scheduleDirtyInlineRowsIdleFlush();
|
|
9074
|
+
return;
|
|
9075
|
+
}
|
|
9076
|
+
this.flushDirtyInlineRows();
|
|
9077
|
+
}, this.dirtyInlineRowsIdleFlushMs);
|
|
9078
|
+
}
|
|
9079
|
+
clearDirtyInlineRowsIdleFlush() {
|
|
9080
|
+
if (this.dirtyInlineRowsIdleTimer === null)
|
|
9081
|
+
return;
|
|
9082
|
+
clearTimeout(this.dirtyInlineRowsIdleTimer);
|
|
9083
|
+
this.dirtyInlineRowsIdleTimer = null;
|
|
8409
9084
|
}
|
|
8410
9085
|
reconcileDirtyInlineRowsAfterRemoval(removedIndex) {
|
|
8411
9086
|
const shifted = new Set();
|
|
@@ -8435,6 +9110,37 @@ class AgridComponent {
|
|
|
8435
9110
|
datasource,
|
|
8436
9111
|
};
|
|
8437
9112
|
}
|
|
9113
|
+
buildServerQuery() {
|
|
9114
|
+
const control = this.control();
|
|
9115
|
+
if (!control)
|
|
9116
|
+
return null;
|
|
9117
|
+
const pageSize = control.pageSize();
|
|
9118
|
+
const serverFiltering = this.serverSideFiltering();
|
|
9119
|
+
const serverPagination = !serverFiltering && control.totalRows() > 0 && pageSize > 0;
|
|
9120
|
+
if (!serverFiltering && !serverPagination)
|
|
9121
|
+
return null;
|
|
9122
|
+
const page = Math.max(1, control.currentPage());
|
|
9123
|
+
const startRow = pageSize > 0 ? (page - 1) * pageSize : 0;
|
|
9124
|
+
const endRow = pageSize > 0 ? startRow + pageSize - 1 : -1;
|
|
9125
|
+
const filters = Object.fromEntries(Object.entries(control.filters()).map(([field, filter]) => [field, {
|
|
9126
|
+
...filter,
|
|
9127
|
+
selectedValues: filter.selectedValues ? [...filter.selectedValues] : null,
|
|
9128
|
+
}]));
|
|
9129
|
+
const sort = this.projection.effectiveSortOrder()
|
|
9130
|
+
.flatMap(field => {
|
|
9131
|
+
const direction = filters[field]?.sort;
|
|
9132
|
+
return direction ? [{ field, direction }] : [];
|
|
9133
|
+
});
|
|
9134
|
+
return {
|
|
9135
|
+
filters,
|
|
9136
|
+
sort,
|
|
9137
|
+
quickFilter: control.quickFilter(),
|
|
9138
|
+
page,
|
|
9139
|
+
pageSize,
|
|
9140
|
+
startRow,
|
|
9141
|
+
endRow,
|
|
9142
|
+
};
|
|
9143
|
+
}
|
|
8438
9144
|
constructor() {
|
|
8439
9145
|
// Keep one datasource identity so selection/controllers are not reset whenever source data
|
|
8440
9146
|
// causes the computed pivot rows to be regenerated.
|
|
@@ -8452,6 +9158,19 @@ class AgridComponent {
|
|
|
8452
9158
|
// Publish the live filtered/sorted rows so charts (and other consumers) can react to filters.
|
|
8453
9159
|
effect(() => this.provider().ɵsetVisibleRows(this.ɵvisibleRows()));
|
|
8454
9160
|
this.destroyRef.onDestroy(() => this.provider().ɵsetVisibleRows(null));
|
|
9161
|
+
// Publish one complete query object for signal-backed server data stores.
|
|
9162
|
+
effect(() => {
|
|
9163
|
+
const provider = this.provider();
|
|
9164
|
+
if (this.serverQueryProvider && this.serverQueryProvider !== provider) {
|
|
9165
|
+
this.serverQueryProvider.ɵsetServerQuery(null);
|
|
9166
|
+
}
|
|
9167
|
+
this.serverQueryProvider = provider;
|
|
9168
|
+
const query = this.buildServerQuery();
|
|
9169
|
+
provider.ɵsetServerQuery(query);
|
|
9170
|
+
if (query)
|
|
9171
|
+
this.serverQueryChange.emit(query);
|
|
9172
|
+
});
|
|
9173
|
+
this.destroyRef.onDestroy(() => this.serverQueryProvider?.ɵsetServerQuery(null));
|
|
8455
9174
|
afterRenderEffect(() => {
|
|
8456
9175
|
if (this.firstDataRenderedEmitted)
|
|
8457
9176
|
return;
|
|
@@ -8484,6 +9203,34 @@ class AgridComponent {
|
|
|
8484
9203
|
const activeRowIndex = this.selectedCell()?.rowIndex ?? null;
|
|
8485
9204
|
this.flushDirtyInlineRows(activeRowIndex);
|
|
8486
9205
|
});
|
|
9206
|
+
effect(() => {
|
|
9207
|
+
const cell = this.selectedCell();
|
|
9208
|
+
if (this.lastEmittedCell === undefined && cell === null) {
|
|
9209
|
+
this.lastEmittedCell = null;
|
|
9210
|
+
return;
|
|
9211
|
+
}
|
|
9212
|
+
if (this.sameCell(this.lastEmittedCell ?? null, cell))
|
|
9213
|
+
return;
|
|
9214
|
+
this.lastEmittedCell = cell ? { ...cell } : null;
|
|
9215
|
+
this.cellSelect.emit(this.resolveCurrentCell(cell));
|
|
9216
|
+
});
|
|
9217
|
+
effect(() => {
|
|
9218
|
+
if (this.formulaBarFocused())
|
|
9219
|
+
return;
|
|
9220
|
+
const cell = this.selectedCell();
|
|
9221
|
+
const editing = this.editingCell();
|
|
9222
|
+
if (!cell) {
|
|
9223
|
+
this.formulaBarDraft.set('');
|
|
9224
|
+
return;
|
|
9225
|
+
}
|
|
9226
|
+
if (editing?.rowIndex === cell.rowIndex && editing.colIndex === cell.colIndex) {
|
|
9227
|
+
this.formulaBarDraft.set(String(this.currentDraft() ?? ''));
|
|
9228
|
+
return;
|
|
9229
|
+
}
|
|
9230
|
+
const row = this.dataSource().rows()[cell.rowIndex];
|
|
9231
|
+
const col = this.visibleColDefs()[cell.colIndex];
|
|
9232
|
+
this.formulaBarDraft.set(row && col ? String(row[col.field] ?? '') : '');
|
|
9233
|
+
});
|
|
8487
9234
|
afterNextRender(() => {
|
|
8488
9235
|
this.viewReady = true;
|
|
8489
9236
|
this.syncColumnViewportMetrics();
|
|
@@ -8547,6 +9294,20 @@ class AgridComponent {
|
|
|
8547
9294
|
return;
|
|
8548
9295
|
this.navigationController.revealRow(added.index);
|
|
8549
9296
|
});
|
|
9297
|
+
effect(() => {
|
|
9298
|
+
const control = this.control();
|
|
9299
|
+
if (!control)
|
|
9300
|
+
return;
|
|
9301
|
+
control.ɵfilterReapplyRevision();
|
|
9302
|
+
this.dataSource().ɵreapplyFiltersToAddedRows();
|
|
9303
|
+
});
|
|
9304
|
+
effect(() => {
|
|
9305
|
+
const control = this.control();
|
|
9306
|
+
if (!control)
|
|
9307
|
+
return;
|
|
9308
|
+
const hasDeferredRows = this.dataSource().ɵunfilteredAddedRows().size > 0;
|
|
9309
|
+
control.ɵsetFilterReapplyNeeded(hasDeferredRows && control.hasAnyActiveFilter());
|
|
9310
|
+
});
|
|
8550
9311
|
// Deselect when clicking outside the grid.
|
|
8551
9312
|
const onOutsidePointerDown = (e) => {
|
|
8552
9313
|
const isInsideGrid = this._hostEl.nativeElement.contains(e.target);
|
|
@@ -8566,6 +9327,7 @@ class AgridComponent {
|
|
|
8566
9327
|
this.destroyRef.onDestroy(() => {
|
|
8567
9328
|
this.browser.removeDocumentListener('keydown', onDocumentKeyDown);
|
|
8568
9329
|
this.browser.removeDocumentListener('pointerdown', onOutsidePointerDown);
|
|
9330
|
+
this.clearDirtyInlineRowsIdleFlush();
|
|
8569
9331
|
if (this.quickFilterTimer !== null)
|
|
8570
9332
|
clearTimeout(this.quickFilterTimer);
|
|
8571
9333
|
});
|
|
@@ -8622,6 +9384,10 @@ class AgridComponent {
|
|
|
8622
9384
|
getItemOriginalIndex(item) {
|
|
8623
9385
|
return isDataRowItem(item) ? item.originalIndex : null;
|
|
8624
9386
|
}
|
|
9387
|
+
/** @internal 1-based row number for visible data rows. */
|
|
9388
|
+
visibleRowNumber(item) {
|
|
9389
|
+
return isDataRowItem(item) ? this.rowNumbers().get(item.originalIndex) ?? null : null;
|
|
9390
|
+
}
|
|
8625
9391
|
/** @internal True when the item is a master/detail panel row. */
|
|
8626
9392
|
isDetailRowItem(item) {
|
|
8627
9393
|
return isDetailRowItem(item);
|
|
@@ -8924,6 +9690,10 @@ class AgridComponent {
|
|
|
8924
9690
|
return this.columnMenuController.hasMultiSort();
|
|
8925
9691
|
}
|
|
8926
9692
|
getTextFilter(field) { return this.columnMenuController.getTextFilter(field); }
|
|
9693
|
+
/** @internal Complete filter snapshot for custom filter components. */
|
|
9694
|
+
getColumnFilter(field) {
|
|
9695
|
+
return this.control()?.getFilter(field) ?? { text: '', selectedValues: null, sort: null };
|
|
9696
|
+
}
|
|
8927
9697
|
/** @internal Condition input type for a column, or `null` when unsupported. */
|
|
8928
9698
|
getMenuFilterType(field) {
|
|
8929
9699
|
return this.columnMenuController.getFilterType(field);
|
|
@@ -9050,6 +9820,70 @@ class AgridComponent {
|
|
|
9050
9820
|
}
|
|
9051
9821
|
/** @internal */
|
|
9052
9822
|
onDraftChange(value) { this.editController.setDraft(value); }
|
|
9823
|
+
/** @internal */
|
|
9824
|
+
onFormulaBarFocus() {
|
|
9825
|
+
this.formulaBarFocused.set(true);
|
|
9826
|
+
this.formulaBarEditCell = this.selectedCell();
|
|
9827
|
+
}
|
|
9828
|
+
/** @internal */
|
|
9829
|
+
onFormulaBarInput(event) {
|
|
9830
|
+
const value = event.target.value;
|
|
9831
|
+
this.formulaBarEditCell ??= this.selectedCell();
|
|
9832
|
+
this.formulaBarDraft.set(value);
|
|
9833
|
+
const cell = this.selectedCell();
|
|
9834
|
+
const editing = this.editingCell();
|
|
9835
|
+
if (cell && editing?.rowIndex === cell.rowIndex && editing.colIndex === cell.colIndex) {
|
|
9836
|
+
this.editController.setDraft(value);
|
|
9837
|
+
}
|
|
9838
|
+
}
|
|
9839
|
+
/** @internal */
|
|
9840
|
+
onFormulaBarBlur() {
|
|
9841
|
+
if (!this.formulaBarFocused())
|
|
9842
|
+
return;
|
|
9843
|
+
this.commitFormulaBar(this.formulaBarEditCell);
|
|
9844
|
+
this.finishFormulaBarInteraction();
|
|
9845
|
+
}
|
|
9846
|
+
/** @internal */
|
|
9847
|
+
onFormulaBarKeydown(event) {
|
|
9848
|
+
event.stopPropagation();
|
|
9849
|
+
if (event.key === 'Enter') {
|
|
9850
|
+
event.preventDefault();
|
|
9851
|
+
if (this.commitFormulaBar()) {
|
|
9852
|
+
this.finishFormulaBarInteraction();
|
|
9853
|
+
this.wrapperEl().nativeElement.focus();
|
|
9854
|
+
}
|
|
9855
|
+
}
|
|
9856
|
+
else if (event.key === 'Escape') {
|
|
9857
|
+
event.preventDefault();
|
|
9858
|
+
this.resetFormulaBarDraft();
|
|
9859
|
+
}
|
|
9860
|
+
}
|
|
9861
|
+
/** @internal */
|
|
9862
|
+
commitFormulaBar(targetCell = this.formulaBarEditCell ?? this.selectedCell()) {
|
|
9863
|
+
const cell = targetCell;
|
|
9864
|
+
if (!cell)
|
|
9865
|
+
return true;
|
|
9866
|
+
const editing = this.editingCell();
|
|
9867
|
+
if (editing?.rowIndex === cell.rowIndex && editing.colIndex === cell.colIndex) {
|
|
9868
|
+
return this.editController.commit();
|
|
9869
|
+
}
|
|
9870
|
+
return this.editController.setCellValue(cell.rowIndex, cell.colIndex, this.formulaBarDraft());
|
|
9871
|
+
}
|
|
9872
|
+
finishFormulaBarInteraction() {
|
|
9873
|
+
this.formulaBarFocused.set(false);
|
|
9874
|
+
this.formulaBarEditCell = null;
|
|
9875
|
+
this.resetFormulaBarDraft();
|
|
9876
|
+
}
|
|
9877
|
+
resetFormulaBarDraft() {
|
|
9878
|
+
const cell = this.selectedCell();
|
|
9879
|
+
if (!cell) {
|
|
9880
|
+
this.formulaBarDraft.set('');
|
|
9881
|
+
return;
|
|
9882
|
+
}
|
|
9883
|
+
const row = this.dataSource().rows()[cell.rowIndex];
|
|
9884
|
+
const col = this.visibleColDefs()[cell.colIndex];
|
|
9885
|
+
this.formulaBarDraft.set(row && col ? String(row[col.field] ?? '') : '');
|
|
9886
|
+
}
|
|
9053
9887
|
/** @internal A custom cell editor requested a commit (e.g. picking a value). */
|
|
9054
9888
|
onEditorCommit() { this.editController.commit(); }
|
|
9055
9889
|
/** @internal A custom cell editor requested cancellation. */
|
|
@@ -9097,6 +9931,8 @@ class AgridComponent {
|
|
|
9097
9931
|
}
|
|
9098
9932
|
/** @internal Main keyboard handler delegated from the wrapper div. */
|
|
9099
9933
|
onKeyDown(event) {
|
|
9934
|
+
if (this.isToolbarInputEvent(event))
|
|
9935
|
+
return;
|
|
9100
9936
|
if (event.key === 'Escape' && this.closeOpenMenus()) {
|
|
9101
9937
|
event.preventDefault();
|
|
9102
9938
|
event.stopPropagation();
|
|
@@ -9112,6 +9948,12 @@ class AgridComponent {
|
|
|
9112
9948
|
return;
|
|
9113
9949
|
this.navigationController.handleKeyDown(event);
|
|
9114
9950
|
}
|
|
9951
|
+
isToolbarInputEvent(event) {
|
|
9952
|
+
const target = event.target;
|
|
9953
|
+
if (!target?.closest('.ag-toolbar'))
|
|
9954
|
+
return false;
|
|
9955
|
+
return target.matches('input, textarea, select, [contenteditable="true"]');
|
|
9956
|
+
}
|
|
9115
9957
|
/** @internal Clears cell navigation while a header filter control owns focus. */
|
|
9116
9958
|
onGridFocusIn(event) {
|
|
9117
9959
|
if (event.target?.closest('.ag-filter-input, .ag-filter-menu')) {
|
|
@@ -9437,6 +10279,10 @@ class AgridComponent {
|
|
|
9437
10279
|
this.columnMenuController.toggleValue(field, rawStr);
|
|
9438
10280
|
}
|
|
9439
10281
|
/** @internal */
|
|
10282
|
+
onMenuReplaceFilter(field, filter) {
|
|
10283
|
+
this.columnMenuController.replaceFilter(field, filter);
|
|
10284
|
+
}
|
|
10285
|
+
/** @internal */
|
|
9440
10286
|
onSidebarToggleColumn(field) {
|
|
9441
10287
|
this.columnMenuController.toggleColumnVisibility(field);
|
|
9442
10288
|
this.emitSettingsChange();
|
|
@@ -9462,6 +10308,16 @@ class AgridComponent {
|
|
|
9462
10308
|
const end = Math.max(range.end, range.start + model.blockSize) + model.blockSize;
|
|
9463
10309
|
model.ensureRange(start, end);
|
|
9464
10310
|
}
|
|
10311
|
+
/** Refresh the attached server-side row model and optionally reset vertical scroll to row zero. */
|
|
10312
|
+
refreshServerSideRows(options = {}) {
|
|
10313
|
+
const model = this.serverSideRowModel();
|
|
10314
|
+
if (!model)
|
|
10315
|
+
return;
|
|
10316
|
+
model.refresh({ purge: options.purge });
|
|
10317
|
+
if (options.resetScroll && this.viewReady)
|
|
10318
|
+
this.viewport().scrollToIndex(0);
|
|
10319
|
+
queueMicrotask(() => this.ensureServerRowsVisible());
|
|
10320
|
+
}
|
|
9465
10321
|
/** @internal Keeps the row-delete prompt visible while columns scroll horizontally. */
|
|
9466
10322
|
onHorizontalScroll() {
|
|
9467
10323
|
this.syncColumnViewportMetrics();
|
|
@@ -9574,7 +10430,7 @@ class AgridComponent {
|
|
|
9574
10430
|
return this.columnSizing.getWidthToken(col);
|
|
9575
10431
|
}
|
|
9576
10432
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9577
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridComponent, isStandalone: true, selector: "agrid", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellEdit: "cellEdit", recordEdit: "recordEdit", rowRemoved: "rowRemoved", prepareAddRecord: "prepareAddRecord", rowReorder: "rowReorder", rowSelect: "rowSelect", rowMark: "rowMark", columnMark: "columnMark", columnHeaderAction: "columnHeaderAction", firstDataRendered: "firstDataRendered", rowDoubleClicked: "rowDoubleClicked", rowClick: "rowClick", treeNodeClick: "treeNodeClick", settingsChange: "settingsChange", treeNodeDoubleClicked: "treeNodeDoubleClicked", rowChanged: "rowChanged", pageChange: "pageChange", filterChange: "filterChange", sortChange: "sortChange", quickFilterChange: "quickFilterChange", validationFailed: "validationFailed", cellInfo: "cellInfo", menuBarAction: "menuBarAction", detailAction: "detailAction" }, host: { properties: { "class.ag-zebra": "zebraStripes()", "style.min-height": "minHeight()", "style.max-height": "maxHeight()" } }, viewQueries: [{ propertyName: "viewport", first: true, predicate: ["scrollViewport"], descendants: true, isSignal: true }, { propertyName: "pinnedViewport", first: true, predicate: ["pinnedViewport"], descendants: true, isSignal: true }, { propertyName: "rightPinnedViewport", first: true, predicate: ["rightPinnedViewport"], descendants: true, isSignal: true }, { propertyName: "wrapperEl", first: true, predicate: ["wrapper"], descendants: true, isSignal: true }, { propertyName: "horizontalScrollerEl", first: true, predicate: ["horizontalScroller"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<div #wrapper class=\"ag-wrapper\" tabindex=\"0\" role=\"grid\" [attr.aria-label]=\"localeText().grid\"\n [attr.aria-rowcount]=\"ariaRowCount()\" [attr.aria-colcount]=\"ariaColCount()\"\n [attr.aria-multiselectable]=\"rowSelection() === 'multi' ? 'true' : null\"\n [attr.aria-readonly]=\"readonlyGrid() ? 'true' : null\" [attr.aria-busy]=\"loading() ? 'true' : null\"\n (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\" (focusin)=\"onGridFocusIn($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu(); closeMenuBarMenu()\">\n @if (visibleMenuBarItems().length > 0 || enableQuickFilter()) {\n <div class=\"ag-toolbar\">\n @if (visibleMenuBarItems().length > 0) {\n <agrid-menu-bar [items]=\"visibleMenuBarItems()\" [context]=\"menuBarContext()\" [label]=\"localeText().actions\"\n [openItemId]=\"openMenuBarItemId()\" (openItemIdChange)=\"onMenuBarOpenItemChange($event)\"\n (action)=\"onMenuBarAction($event)\" />\n }\n @if (enableQuickFilter()) {\n <input class=\"ag-quick-filter\" type=\"search\" [value]=\"quickFilterValue()\" (input)=\"onQuickFilterInput($event)\"\n [placeholder]=\"localeText().quickFilterPlaceholder\" [attr.aria-label]=\"localeText().quickFilterPlaceholder\" />\n }\n </div>\n }\n <div class=\"ag-main-area\">\n <div class=\"ag-grid-split\" [class.ag-has-right-pane]=\"hasRightPinnedPane()\">\n @if (hasPinnedPane()) {\n <div class=\"ag-pinned-pane\" [style.width.px]=\"pinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"left\"\n [headerGroups]=\"pinnedHeaderGroups()\"\n [columns]=\"pinnedHeaderColumns()\"\n [gridTemplateColumns]=\"pinnedGridTemplateColumns()\"\n [paneWidth]=\"pinnedPaneWidth()\"\n [totalWidth]=\"pinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #leftRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\" [attr.data-control]=\"true\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isPinnedPaneRowSelected(item)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? pinnedGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell\" role=\"rowheader\" aria-colindex=\"1\"\n [class.ag-control-cell--reorder]=\"allowRowReorder()\"\n [class.ag-control-cell--marking]=\"enableRowMarking()\"\n (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\"\n (click)=\"onControlCellClick($event, item.originalIndex)\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\">\n @if (canToggleDetail(item)) {\n <button class=\"ag-detail-toggle\" type=\"button\"\n [class.ag-detail-toggle--expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-label]=\"localeText().toggleDetail\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"onDetailToggle(item.originalIndex); $event.stopPropagation()\">\u25B6</button>\n }\n @if (enableRowMarking()) {\n <input class=\"ag-row-marker\" type=\"checkbox\" [checked]=\"isRowMarked(item.originalIndex)\"\n [attr.aria-label]=\"localeText().markRow\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\" (change)=\"toggleRowMarked(item.originalIndex)\" />\n }\n </div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"pinnedColDefs()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell ag-control-cell--reorder ag-ghost-handle\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\">\n @if (showControlColumn()) {\n <div class=\"ag-footer-cell ag-footer-cell--control\" role=\"gridcell\" aria-colindex=\"1\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-last]=\"bc.lastPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"ag-scroll-pane\">\n <div #horizontalScroller class=\"ag-horizontal-scroll\" (scroll)=\"onHorizontalScroll()\">\n <agrid-pane-header\n variant=\"center\"\n [headerGroups]=\"scrollableHeaderGroups()\"\n [columns]=\"scrollableHeaderColumns()\"\n [gridTemplateColumns]=\"scrollableGridTemplateColumns()\"\n [paneWidth]=\"scrollableTotalWidth()\"\n [totalWidth]=\"scrollableTotalWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #bodyRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? scrollableGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (columnWindow().leftWidth > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'1 / span ' + columnWindow().start\"></div>\n }\n @for (bc of virtualScrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"scrollableColDefs()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\"\n (startEdit)=\"onStartEdit(item.originalIndex, ci)\" (draftChange)=\"onDraftChange($event)\"\n (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\" (treeToggle)=\"onTreeToggle(item)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n @if (columnWindowRightSpan() > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'span ' + columnWindowRightSpan()\"></div>\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-add-row-label\" (click)=\"onActivateAddRow()\">\n <span class=\"ag-add-row-icon\">+</span> {{ localeText().addRow }}\n </div>\n } @else if (item === 'ghost') {\n @for (bc of scrollableBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell\" [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else if (isDetailRowItem(item)) {\n <div class=\"ag-detail-panel\" [style.height.px]=\"detailRowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n <div [innerHTML]=\"detailHtml(item)\"></div>\n @if (detailColumn(); as detailCol) {\n <div class=\"ag-detail-column-field\">\n <span class=\"ag-detail-column-label\">{{ detailCol.header }}</span>\n @if (detailActions().length && isDetailFieldEditable(item)) {\n <div class=\"ag-detail-action-bar\" role=\"toolbar\" [attr.aria-label]=\"detailCol.header + localeText().templates\">\n @for (action of detailActions(); track action.id) {\n <button type=\"button\" class=\"ag-detail-action-btn\"\n (click)=\"applyDetailAction(item, action, $event)\">{{ action.label }}</button>\n }\n </div>\n }\n @if (detailEditingRow() === item.detailFor) {\n <textarea class=\"ag-detail-column-textarea\" [attr.data-detail-row]=\"item.detailFor\"\n [class.ag-detail-column-textarea--invalid]=\"!!detailValidationError()\"\n [value]=\"detailDraft()\" (input)=\"onDetailDraftInput($event)\"\n (pointerdown)=\"$event.stopPropagation()\"\n (keydown)=\"onDetailEditorKeydown(item, $event)\"\n (blur)=\"commitDetailFieldEdit(item)\"></textarea>\n @if (detailValidationError(); as message) {\n <span class=\"ag-detail-column-error\" role=\"alert\">{{ message }}</span>\n }\n } @else {\n <div class=\"ag-detail-column-value\" [class.ag-detail-column-value--editable]=\"isDetailFieldEditable(item)\"\n [attr.tabindex]=\"isDetailFieldEditable(item) ? 0 : null\"\n (click)=\"startDetailFieldEdit(item, $event)\"\n (keydown.enter)=\"startDetailFieldEdit(item, $event)\">{{ detailFieldDisplay(item) }}</div>\n }\n </div>\n }\n </div>\n } @else if (isPathTreeNodeItem(item)) {\n <div class=\"ag-path-tree-content\" [style.min-width.px]=\"scrollableTotalWidth()\"\n [style.padding-left.px]=\"treeRowLevel(item) * 16 + 8\"\n (click)=\"onTreeNodeClick(item); $event.stopPropagation()\"\n (dblclick)=\"onTreeNodeDoubleClick(item); $event.stopPropagation()\">\n <button type=\"button\" class=\"ag-tree-twisty\" [class.ag-tree-twisty--expanded]=\"treeRowExpanded(item)\"\n [attr.aria-expanded]=\"treeRowExpanded(item)\"\n (click)=\"onTreeToggle(item); $event.stopPropagation()\">\u25B6</button>\n <span>{{ pathTreeLabel(item) }}</span>\n @if (item.aggregates; as aggregates) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (col.field !== treeConfig()!.treeField && aggregates[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggregates[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n } @else {\n <div class=\"ag-group-header-content\" [style.min-width.px]=\"scrollableTotalWidth()\">\n <div class=\"ag-group-header-main\"\n (click)=\"onGroupHeaderClick(item.groupLabel); $event.stopPropagation()\">\n <span class=\"ag-group-icon\" [class.ag-group-icon--expanded]=\"!item.collapsed\">\u25B6</span>\n <span class=\"ag-group-label\">{{ item.groupLabel }}</span>\n @if (groupActions().length > 0) {\n <button class=\"ag-group-actions-btn\" [title]=\"localeText().actions\"\n (click)=\"openGroupActionsMenu($event, item.groupLabel)\">\u22EE</button>\n }\n <span class=\"ag-group-count\">{{ item.count }}</span>\n @if (getGroupDescription(item.groupLabel); as desc) {\n <span class=\"ag-group-description\">{{ desc }}</span>\n }\n @if (item.aggregates; as aggs) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (hasAggregate(col) && aggs[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggs[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n </div>\n }\n @if (isDataRowItem(item) && isRowPendingDelete(item.originalIndex)) {\n <div class=\"ag-delete-confirmation\" role=\"alertdialog\" [attr.aria-label]=\"localeText().confirmDeleteRow\"\n [style.left.px]=\"deleteConfirmationLeft()\" [style.width.px]=\"deleteConfirmationWidth() || null\"\n (pointerdown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <span class=\"ag-delete-confirmation-text\">{{ localeText().confirmDeleteRow }}</span>\n <button class=\"ag-delete-confirmation-btn ag-delete-confirmation-btn--yes\" type=\"button\"\n (click)=\"confirmPendingRowDelete()\">{{ localeText().confirmYes }}</button>\n <button class=\"ag-delete-confirmation-btn\" type=\"button\" data-delete-confirm-no\n (click)=\"cancelRowDelete()\">{{ localeText().confirmNo }}</button>\n </div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (bc of scrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (hasRightPinnedPane()) {\n <div class=\"ag-pinned-pane ag-pinned-pane--right\" [style.width.px]=\"rightPinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"right\"\n [headerGroups]=\"rightHeaderGroups()\"\n [columns]=\"rightHeaderColumns()\"\n [gridTemplateColumns]=\"rightGridTemplateColumns()\"\n [paneWidth]=\"rightPinnedPaneWidth()\"\n [totalWidth]=\"rightPinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #rightRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(item)\"\n [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"rightPinnedColDefs()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\" [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--pinned]=\"true\" [class.ag-cell--pinned-first]=\"bc.firstRightPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (bc of rightBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-first]=\"bc.firstRightPinned\">{{ getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [agridVariableRowSize]=\"itemSizes()\" [style.width.px]=\"rightPinnedPaneWidth()\"\n (scroll)=\"onRightPinnedBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-first]=\"bc.firstRightPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (loading()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ localeText().loading }}</div>\n } @else if (isEmpty()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ emptyTextLabel() }}</div>\n }\n\n @if (showSidebar()) {\n <agrid-sidebar [open]=\"sidebarOpen()\" [activeTab]=\"sidebarTab()\" [columns]=\"colDefs()\"\n [pivotColumns]=\"sidebarPivotColumns()\" [pivotConfig]=\"provider().pivotConfig\" [headerGroups]=\"headerGroups()\"\n [row]=\"sidebarRow()\" [rowIndex]=\"selectedRowIndex()\" [hiddenColumns]=\"sidebarHiddenColumns()\" [locale]=\"locale()\"\n [localeText]=\"localeText()\" [readonlyGrid]=\"readonlyGrid()\" [useSidebarEditor]=\"useSidebarEditor()\"\n [isCellEditable]=\"isCellEditableForRow\" [errors]=\"sidebarValidationErrors()\" (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\" (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (toggleColumnGroup)=\"onSidebarToggleColumnGroup($event.fields, $event.visible)\"\n (pivotChange)=\"onSidebarPivotChange($event)\" (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\" />\n }\n </div><!-- /.ag-main-area -->\n\n @if (!hideGridStatusBar() && selectionSummaryDisplay(); as summary) {\n <div class=\"ag-status-bar\" role=\"status\" aria-live=\"polite\">\n <span><strong>{{ localeText().aggregateCount }}:</strong> {{ summary.count }}</span>\n <span><strong>{{ localeText().aggregateSum }}:</strong> {{ summary.sum }}</span>\n <span><strong>{{ localeText().aggregateAvg }}:</strong> {{ summary.average }}</span>\n <span><strong>{{ localeText().aggregateMin }}:</strong> {{ summary.min }}</span>\n <span><strong>{{ localeText().aggregateMax }}:</strong> {{ summary.max }}</span>\n </div>\n }\n\n @if (showPagination()) {\n <nav class=\"ag-pagination\" [attr.aria-label]=\"localeText().pagination\">\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().firstPage\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToPrevPage()\">\u2039</button>\n <span class=\"ag-page-info\" aria-live=\"polite\">{{ control()!.currentPage() }} / {{ totalPages() }}</span>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().next\" (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\" (click)=\"goToLastPage()\">\u00BB</button>\n <span class=\"ag-page-count\">{{ localeText().rows(filteredRowCount()) }}</span>\n </nav>\n }\n\n @if (findOpen()) {\n <agrid-find-panel [query]=\"findQuery()\" [matchCount]=\"findMatches().length\" [activeIndex]=\"findActiveIndex()\"\n [localeText]=\"localeText()\" (queryChange)=\"onFindInput($event)\" (previous)=\"goToFindMatch(-1)\"\n (next)=\"goToFindMatch(1)\" (close)=\"closeFind()\" />\n }\n\n <!-- Row context menu -->\n @if (contextMenu(); as menu) {\n @if(hasContextMenuEntries()) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @if (!treeConfig()) {\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n }\n @if (!readonlyGrid()) {\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n }\n </div>\n }\n }\n\n <!-- Cell context menu -->\n @if (cellContextMenuState(); as menu) {\n @let col = getColDef(menu.field)!;\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyCellToClipboard(menu.rowIndex, col)\">{{\n localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.rowIndex)\">{{ localeText().copyRow\n }}</button>\n @if (!treeConfig()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n }\n @if (allowAddRows() && !readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex)\">{{ localeText().insertRowAbove\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{\n localeText().insertRowBelow }}</button>\n }\n @if (!readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">{{\n localeText().deleteRow }}</button>\n }\n @if (cellMenuItems().length) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @for (item of cellMenuItems(); track $index) {\n @if (item === null) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" [class.ag-context-item--danger]=\"item.danger\"\n [disabled]=\"item.disabled\" (click)=\"runCellMenuItem(item, menu)\">{{\n item.label }}</button>\n }\n }\n }\n </div>\n }\n\n <!-- Group actions menu -->\n @if (groupActionsMenu(); as menu) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @for (action of groupActions(); track action.label) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onGroupAction(action, menu.label)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <!-- Filter dropdown -->\n @if (filterMenu(); as menu) {\n <agrid-column-menu [x]=\"menu.x\" [y]=\"menu.y\" [header]=\"getColDef(menu.field)?.header ?? menu.field\"\n [sortDir]=\"getSort(menu.field)\" [sortable]=\"menu.mode === 'column' && sortOption() !== 'none'\"\n [showColumnActions]=\"menu.mode === 'column' && !!control()\"\n [showAggregationActions]=\"menu.mode === 'column' && pivotRowColumnField()===null\"\n [pinned]=\"getColumnPinState(menu.field)\" [groupable]=\"menu.mode === 'column' && !!getColDef(menu.field)?.groupable\"\n [grouped]=\"isGroupedByField(menu.field)\" [filterable]=\"!!getColDef(menu.field)?.filterable\"\n [showFilterActions]=\"menu.mode === 'column'\"\n [showValueFilter]=\"menu.mode === 'column' && (!serverSideFiltering() || !!getColDef(menu.field)?.values?.length)\"\n [filterType]=\"getMenuFilterType(menu.field)\" [operator]=\"getMenuOperator(menu.field)\"\n [operand]=\"getMenuOperand(menu.field)\" [operand2]=\"getMenuOperand2(menu.field)\"\n (operatorChange)=\"onMenuOperatorChange(menu.field, $event)\"\n (operandChange)=\"onMenuOperandChange(menu.field, $event)\"\n (operand2Change)=\"onMenuOperand2Change(menu.field, $event)\" [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\" [valueItems]=\"(serverSideFiltering() && !getColDef(menu.field)?.values?.length)\n || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\" [localeText]=\"localeText()\"\n [sortPriority]=\"getSortPriority(menu.field)\" [hasMultiSort]=\"hasMultiSort()\" (sort)=\"onMenuSort(menu.field, $event)\"\n (resetSort)=\"onMenuResetSort(menu.field, $event)\" (autosize)=\"onMenuAutosizeColumn(menu.field)\"\n (togglePin)=\"onMenuTogglePin(menu.field)\" (togglePinRight)=\"onMenuTogglePinRight(menu.field)\"\n (hide)=\"onMenuHideColumn(menu.field)\" (toggleGroup)=\"onMenuToggleGroupBy(menu.field)\"\n (clearFilter)=\"onMenuClearFilter(menu.field)\" (clearAll)=\"onMenuClearAll()\"\n (searchChange)=\"onFilterMenuSearch($event)\" (toggleAll)=\"onMenuToggleAll(menu.field)\"\n (toggleValue)=\"onMenuToggleValue(menu.field, $event)\" [aggregate]=\"getEffectiveAggregate(getColDef(menu.field)!)\"\n [customItems]=\"menu.mode === 'column' ? getColDef(menu.field)?.headerMenuItems ?? [] : []\"\n (customAction)=\"onColumnHeaderAction(menu.field, $event)\"\n (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\n }\n\n @if (columnDragPreview(); as preview) {\n <div class=\"ag-column-drag-preview\" [style.left.px]=\"preview.x\" [style.top.px]=\"preview.y\"\n [style.width.px]=\"preview.width\" [style.height.px]=\"preview.height\">\n <span>{{ preview.label }}</span>\n </div>\n }\n</div>\n", styles: ["@layer agrid-defaults{:host{--agrid-color-text: #24292f;--agrid-color-text-muted: #57606a;--agrid-color-accent: #1a73e8;--agrid-color-accent-subtle: #e8f0fe;--agrid-color-accent-fg: #1558b0;--agrid-color-accent-border: #c8d8f8;--agrid-color-danger: #d1242f;--agrid-color-danger-subtle: #fff1f0;--agrid-color-border: #d0d7de;--agrid-color-bg: #ffffff;--agrid-color-bg-subtle: #fafbfc;--agrid-color-bg-muted: #f6f8fa;--agrid-color-shadow: rgba(140, 149, 159, .2);--agrid-color-bg-stripe: #f0f2f5;--agrid-color-cell-changed: #f59e0b;--agrid-color-row-marked: #fff8c5;--agrid-color-column-marked: #e8f0fe;--agrid-color-menu-bg: #ffffff}}:host{display:flex;flex-direction:column;min-height:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--agrid-color-text)}.ag-wrapper{position:relative;display:flex;flex-direction:column;flex:1;min-height:0;border:1px solid var(--agrid-color-border);overflow:hidden;outline:none;border-radius:4px}.ag-state-overlay{position:absolute;inset:34px 0 0;display:flex;align-items:center;justify-content:center;color:var(--agrid-color-text-muted);background:color-mix(in srgb,var(--agrid-color-bg) 78%,transparent);pointer-events:none;z-index:3}.ag-status-bar{display:flex;flex-shrink:0;align-items:center;justify-content:flex-end;gap:16px;min-height:28px;padding:3px 10px;box-sizing:border-box;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);color:var(--agrid-color-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.ag-status-bar strong{color:var(--agrid-color-text);font-weight:600}@media(max-width:640px){.ag-status-bar{justify-content:flex-start;gap:10px;overflow-x:auto}.ag-status-bar span{white-space:nowrap}}.ag-row>agrid-cell,.ag-ghost-cell,.ag-footer-cell{transition:transform .16s cubic-bezier(.2,0,0,1),opacity .1s ease;will-change:transform}.ag-virtual-col-spacer{pointer-events:none}.ag-loading-row{grid-column:1 / -1;display:flex;align-items:center;padding:0 10px;box-sizing:border-box;border-bottom:1px solid var(--agrid-color-border)}.ag-loading-row span{width:min(220px,55%);height:8px;border-radius:999px;background:color-mix(in srgb,var(--agrid-color-text-muted) 18%,transparent)}.ag-column-reorder-item--dragging{opacity:.12}.ag-column-drag-preview{position:fixed;z-index:1000;display:flex;align-items:flex-start;padding:8px 10px;border:1px solid var(--agrid-color-accent);border-radius:5px;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-bg) 94%,var(--agrid-color-accent));box-shadow:0 10px 28px var(--agrid-color-shadow);font-weight:600;line-height:16px;box-sizing:border-box;pointer-events:none;opacity:.96}.ag-main-area{display:flex;flex:1;min-height:0;overflow:hidden}.ag-grid-split{display:flex;flex:1;min-width:0;min-height:0;overflow:hidden}.ag-pinned-pane{flex-shrink:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-scroll-pane{flex:1;min-width:0;min-height:0;display:flex}.ag-horizontal-scroll{flex:1;min-width:0;min-height:0;overflow-x:auto;overflow-y:hidden;display:flex;flex-direction:column}.ag-body{flex:1;overflow-x:clip;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-horizontal-scroll{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-body::-webkit-scrollbar,.ag-horizontal-scroll::-webkit-scrollbar{width:8px;height:8px}.ag-body::-webkit-scrollbar-track,.ag-horizontal-scroll::-webkit-scrollbar-track{background:transparent}.ag-body::-webkit-scrollbar-thumb,.ag-horizontal-scroll::-webkit-scrollbar-thumb{background:#0000002e;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-body::-webkit-scrollbar-thumb:hover,.ag-horizontal-scroll::-webkit-scrollbar-thumb:hover{background:#00000052;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-pinned-body{overflow:hidden}.ag-right-pinned-body{overflow-y:auto}.ag-has-right-pane .ag-body:not(.ag-pinned-body){scrollbar-width:none}.ag-has-right-pane .ag-body:not(.ag-pinned-body)::-webkit-scrollbar{display:none}.ag-row{display:grid;position:relative;--agrid-row-indication-duration: 1s}.ag-row--pending-delete>:not(.ag-delete-confirmation){opacity:.2;pointer-events:none;transition:opacity .14s ease}.ag-delete-confirmation{position:absolute;top:0;bottom:0;z-index:7;display:flex;align-items:center;justify-content:center;gap:8px;min-width:min(100%,320px);padding:2px 12px;box-sizing:border-box;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-danger-subtle) 88%,transparent);border-block:1px solid color-mix(in srgb,var(--agrid-color-danger) 35%,transparent)}.ag-delete-confirmation-text{font-weight:600;white-space:nowrap}.ag-delete-confirmation-btn{min-width:42px;padding:3px 9px;border:1px solid var(--agrid-color-border);border-radius:4px;color:var(--agrid-color-text);background:var(--agrid-color-bg);font:inherit;cursor:pointer}.ag-delete-confirmation-btn:hover,.ag-delete-confirmation-btn:focus-visible{border-color:var(--agrid-color-accent);outline:none}.ag-delete-confirmation-btn--yes{color:#fff;border-color:var(--agrid-color-danger);background:var(--agrid-color-danger)}.ag-delete-confirmation-btn--yes:hover,.ag-delete-confirmation-btn--yes:focus-visible{border-color:color-mix(in srgb,var(--agrid-color-danger) 75%,#000);background:color-mix(in srgb,var(--agrid-color-danger) 85%,#000)}:host(.ag-zebra) .ag-row--odd agrid-cell:not(.editing){background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-control-cell{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd:hover .ag-control-cell{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned-first{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned-first{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned-first{background:var(--agrid-color-accent-subtle)}.ag-row:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}.ag-row--marked agrid-cell:not(.editing),.ag-row--marked .ag-control-cell{background:var(--agrid-color-row-marked)}.ag-row--marked{box-shadow:inset 3px 0 #bf8700}.ag-row--indicating:after{content:\"\";position:absolute;inset:0;z-index:6;pointer-events:none;background:var(--agrid-row-indication-color);animation:ag-row-indication-fade var(--agrid-row-indication-duration) ease-out forwards}@keyframes ag-row-indication-fade{0%{opacity:.35}to{opacity:0}}.ag-row agrid-cell.ag-column--marked:not(.editing),.ag-footer-cell.ag-column--marked{background:var(--agrid-color-column-marked)}.ag-row--selected.ag-row--marked{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--range-selected:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent-border)}.ag-row agrid-cell.ag-cell--find-match:not(.editing){background:#fff7cc}.ag-row agrid-cell.ag-cell--find-active:not(.editing){background:#ffe58a;box-shadow:inset 0 0 0 2px #b7791f}.ag-row agrid-cell.ag-cell--range-selected.selected:not(.editing){box-shadow:inset 0 0 0 2px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-preview:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing){position:relative}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing):after{content:\"\";position:absolute;right:1px;bottom:1px;width:6px;height:6px;background:var(--agrid-color-accent);border:1px solid var(--agrid-color-bg);box-sizing:border-box;cursor:crosshair;z-index:4}.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}.ag-row--selected{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-control-cell{z-index:2;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);cursor:context-menu;display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;flex-direction:row-reverse}.ag-control-cell:after{content:\"\\22ee\";font-size:11px;color:var(--agrid-color-border);line-height:1}.ag-control-cell:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder{cursor:grab}.ag-control-cell--marking:not(.ag-control-cell--reorder){cursor:pointer}.ag-control-cell--reorder:after{content:\"\\283f\";font-size:13px;color:var(--agrid-color-text)}.ag-control-cell--reorder:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder:active{cursor:grabbing}.ag-row-marker{position:relative;z-index:1;width:14px;height:14px;margin:0;accent-color:var(--agrid-color-accent);cursor:pointer}.ag-ghost-row{background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1.5px var(--agrid-color-accent);pointer-events:none;animation:ag-ghost-in .1s ease}@keyframes ag-ghost-in{0%{opacity:0}to{opacity:1}}.ag-ghost-handle:after{color:var(--agrid-color-accent)!important}.ag-ghost-cell{display:flex;align-items:center;padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;border-right:1px solid var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-size:13px;box-sizing:border-box;-webkit-user-select:none;user-select:none}.ag-ghost-cell:last-child{border-right:none}.ag-pinned-row-spacer,.ag-pinned-group-spacer{height:100%;border-bottom:1px solid var(--agrid-color-border);box-sizing:border-box}.ag-pinned-group-spacer{background:var(--agrid-color-bg-muted)}.ag-context-menu{position:fixed;z-index:1000;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:160px;padding:4px 0;font-size:13px}.ag-context-item{display:block;width:100%;padding:6px 16px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit}.ag-context-item:hover{background:var(--agrid-color-bg-muted)}.ag-context-separator{height:1px;background:var(--agrid-color-border);margin:3px 0}.ag-context-item--danger{color:var(--agrid-color-danger)}.ag-context-item--danger:hover{background:var(--agrid-color-danger-subtle)}.ag-group-header-row{display:flex;align-items:stretch;background:var(--agrid-color-bg-muted);border-bottom:1px solid var(--agrid-color-border);overflow:hidden}.ag-path-tree-content{display:flex;align-items:center;gap:4px;height:100%;box-sizing:border-box;color:var(--agrid-color-text);font-weight:600;border-bottom:1px solid var(--agrid-color-border)}.ag-path-tree-content .ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;color:inherit;background:transparent;cursor:pointer;font-size:10px;transition:transform .12s ease}.ag-path-tree-content .ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-group-header-content{display:flex;align-items:stretch;height:100%;width:100%;-webkit-user-select:none;user-select:none}.ag-group-header-main{display:flex;align-items:center;gap:6px;padding:0 10px;flex:1;min-width:0;cursor:pointer}.ag-group-header-main:hover{background:var(--agrid-color-bg-subtle)}.ag-group-description{font-size:11px;color:var(--agrid-color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-group-actions-btn{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border:none;background:none;border-radius:3px;cursor:pointer;color:var(--agrid-color-text-muted);font-size:14px;padding:0}.ag-group-actions-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text)}.ag-group-icon{font-size:9px;color:var(--agrid-color-text-muted);line-height:1;display:inline-block;transition:transform .15s ease}.ag-group-icon--expanded{transform:rotate(90deg)}.ag-group-label{font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-group-count{font-size:11px;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);border:1px solid var(--agrid-color-border);border-radius:10px;padding:0 7px;line-height:16px}.ag-group-aggregates{display:inline-flex;align-items:center;gap:10px;margin-left:4px;flex-wrap:wrap}.ag-group-aggregate{font-size:11px;color:var(--agrid-color-text);white-space:nowrap}.ag-group-aggregate-col{color:var(--agrid-color-text-muted);margin-right:4px}.ag-group-aggregate-op{color:var(--agrid-color-text-muted);margin-right:3px}.ag-footer{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-top:2px solid var(--agrid-color-border)}.ag-footer-cell{display:flex;align-items:center;gap:4px;padding:0 6px;height:30px;border-right:1px solid var(--agrid-color-border);box-sizing:border-box;overflow:hidden;white-space:nowrap;font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-footer-cell:last-child{border-right:none}.ag-footer-cell--control{background:var(--agrid-color-bg-subtle);border-right:1px solid var(--agrid-color-border)}.ag-footer-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-footer-label{font-size:10px;font-weight:400;color:var(--agrid-color-text-muted);flex-shrink:0}.ag-pagination{display:flex;align-items:center;gap:4px;padding:0 10px;height:34px;flex-shrink:0;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted);font-size:12px;color:var(--agrid-color-text-muted)}.ag-page-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;border:1px solid var(--agrid-color-border);border-radius:3px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;cursor:pointer;padding:0;line-height:1}.ag-page-btn:hover:not(:disabled){background:var(--agrid-color-bg-muted);border-color:var(--agrid-color-text-muted)}.ag-page-btn:disabled{opacity:.35;cursor:default}.ag-page-info{padding:0 6px;font-weight:500;color:var(--agrid-color-text);min-width:48px;text-align:center}.ag-page-count{margin-left:auto;color:var(--agrid-color-text-muted)}.ag-add-row{border-bottom:1px dashed var(--agrid-color-border);color:var(--agrid-color-text-muted);cursor:pointer}.ag-add-row:hover .ag-add-row-label{background:var(--agrid-color-bg-muted)}.ag-add-row--selected .ag-add-row-label{outline:2px solid var(--agrid-color-accent);outline-offset:-2px}.ag-add-row-label{display:flex;align-items:center;gap:4px;height:100%;padding:0 6px;font-size:12px;-webkit-user-select:none;user-select:none}.ag-add-row-icon{font-size:16px;line-height:1;color:var(--agrid-color-text-muted)}.ag-pinned-pane--right{border-left:1px solid var(--agrid-color-border);border-right:none;box-shadow:-3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned{background:var(--agrid-color-bg)}.ag-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned-first{box-shadow:none}.ag-row:hover .ag-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-row--selected .ag-cell--pinned,.ag-row .ag-cell--pinned.ag-cell--range-selected,.ag-row .ag-cell--pinned.ag-cell--fill-preview{background:var(--agrid-color-accent-subtle)}.ag-row .ag-cell--pinned.ag-cell--find-match{background:#fff7cc}.ag-row .ag-cell--pinned.ag-cell--find-active{background:#ffe58a}.ag-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;padding:6px 8px;border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle)}.ag-quick-filter{margin-left:auto;width:100%;max-width:260px;height:30px;padding:0 10px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text)}.ag-quick-filter:focus{border-color:var(--agrid-color-accent-border)}.ag-detail-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;font-size:9px;line-height:1;color:var(--agrid-color-text-muted);transition:transform .12s ease,color .12s ease}.ag-detail-toggle:hover{color:var(--agrid-color-text)}.ag-detail-toggle--expanded{transform:rotate(90deg)}.ag-detail-row{display:block;position:relative;box-sizing:border-box}.ag-detail-panel{box-sizing:border-box;height:100%;overflow:auto;padding:8px 12px;background:var(--agrid-color-bg-subtle);border-bottom:1px solid var(--agrid-color-border)}.ag-detail-column-field{display:grid;gap:4px;margin-top:10px}.ag-detail-column-label{color:var(--agrid-color-text-muted);font-size:10px;font-weight:600;letter-spacing:.4px;text-transform:uppercase}.ag-detail-action-bar{display:flex;flex-wrap:wrap;gap:6px}.ag-detail-action-btn{border:1px solid var(--agrid-color-border);border-radius:3px;padding:4px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:12px;line-height:1.3;cursor:pointer}.ag-detail-action-btn:hover,.ag-detail-action-btn:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-value,.ag-detail-column-textarea{min-height:54px;box-sizing:border-box;border:1px solid var(--agrid-color-border);border-radius:3px;padding:7px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;line-height:1.4;white-space:pre-wrap}.ag-detail-column-value--editable{cursor:text}.ag-detail-column-value--editable:hover,.ag-detail-column-value--editable:focus,.ag-detail-column-textarea:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-textarea{width:100%;height:120px;resize:vertical;user-select:text;-webkit-user-select:text;cursor:text}.ag-detail-column-textarea--invalid{border-color:var(--agrid-color-danger)}.ag-detail-column-error{color:var(--agrid-color-danger);font-size:12px}.ag-pinned-rows{position:relative;z-index:3;flex:none;background:var(--agrid-color-bg)}.ag-pinned-rows--top{box-shadow:0 2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows--bottom{box-shadow:0 -2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows .ag-row{background:var(--agrid-color-bg-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: AgridVariableRowSizeDirective, selector: "cdk-virtual-scroll-viewport[agridVariableRowSize]", inputs: ["agridVariableRowSize"] }, { kind: "component", type: AgridCellComponent, selector: "agrid-cell", inputs: ["localeText", "col", "paneColumns", "rowIndex", "colIndex", "value", "displayValueOverride", "row", "locale", "selected", "editing", "editable", "showInfoIcon", "error", "treeCell", "treeLevel", "treeExpandable", "treeExpanded", "seedChar", "selectTextOnEdit"], outputs: ["treeToggle", "activate", "startEdit", "booleanToggle", "infoClick", "draftChange", "editorCommit", "editorCancel"] }, { kind: "component", type: AgridPaneHeaderComponent, selector: "agrid-pane-header", inputs: ["variant", "headerGroups", "columns", "gridTemplateColumns", "paneWidth", "totalWidth", "hasHeaderGroups", "hasFilterableColumns", "headerRowCount", "showControlColumn", "localeText", "pivotHeaderLabel", "pivotRowColumnField", "hasMultiSort", "filterMenuField", "markedColumnFields"], outputs: ["headerGroupPointerDown", "colHeaderPointerDown", "colHeaderClick", "filterMenuOpen", "filterConditionMenuOpen", "textFilterChange", "resizeKeyDown", "resizeStart", "autosizeColumn"] }, { kind: "component", type: AgridMenuBarComponent, selector: "agrid-menu-bar", inputs: ["items", "context", "label", "openItemId"], outputs: ["action", "openItemIdChange"] }, { kind: "component", type: AgridColumnMenuComponent, selector: "agrid-column-menu", inputs: ["localeText", "x", "y", "header", "sortDir", "sortable", "showColumnActions", "showAggregationActions", "customItems", "pinned", "groupable", "grouped", "filterable", "showFilterActions", "showValueFilter", "filterType", "operator", "operand", "operand2", "search", "allSelected", "valueItems", "sortPriority", "hasMultiSort", "aggregate"], outputs: ["customAction", "operatorChange", "operandChange", "operand2Change", "sort", "resetSort", "autosize", "togglePin", "togglePinRight", "hide", "toggleGroup", "clearFilter", "clearAll", "searchChange", "toggleAll", "toggleValue", "setAggregate"] }, { kind: "component", type: AgridFindPanelComponent, selector: "agrid-find-panel", inputs: ["localeText", "query", "matchCount", "activeIndex"], outputs: ["queryChange", "next", "previous", "close"] }, { kind: "component", type: AgridSidebarComponent, selector: "agrid-sidebar", inputs: ["open", "activeTab", "columns", "pivotColumns", "pivotConfig", "headerGroups", "row", "rowIndex", "hiddenColumns", "locale", "localeText", "readonlyGrid", "useSidebarEditor", "isCellEditable", "errors"], outputs: ["close", "tabChange", "toggleColumn", "toggleColumnGroup", "detailEdit", "save", "pivotChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10433
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridComponent, isStandalone: true, selector: "agrid", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellEdit: "cellEdit", recordEdit: "recordEdit", rowRemoved: "rowRemoved", prepareAddRecord: "prepareAddRecord", rowReorder: "rowReorder", rowSelect: "rowSelect", rowMark: "rowMark", columnMark: "columnMark", columnHeaderAction: "columnHeaderAction", firstDataRendered: "firstDataRendered", rowDoubleClicked: "rowDoubleClicked", rowClick: "rowClick", treeNodeClick: "treeNodeClick", settingsChange: "settingsChange", treeNodeDoubleClicked: "treeNodeDoubleClicked", rowChanged: "rowChanged", pageChange: "pageChange", filterChange: "filterChange", sortChange: "sortChange", serverQueryChange: "serverQueryChange", quickFilterChange: "quickFilterChange", validationFailed: "validationFailed", cellInfo: "cellInfo", cellSelect: "cellSelect", menuBarAction: "menuBarAction", detailAction: "detailAction" }, host: { properties: { "class.ag-zebra": "zebraStripes()", "style.min-height": "minHeight()", "style.max-height": "maxHeight()" } }, viewQueries: [{ propertyName: "viewport", first: true, predicate: ["scrollViewport"], descendants: true, isSignal: true }, { propertyName: "pinnedViewport", first: true, predicate: ["pinnedViewport"], descendants: true, isSignal: true }, { propertyName: "rightPinnedViewport", first: true, predicate: ["rightPinnedViewport"], descendants: true, isSignal: true }, { propertyName: "wrapperEl", first: true, predicate: ["wrapper"], descendants: true, isSignal: true }, { propertyName: "horizontalScrollerEl", first: true, predicate: ["horizontalScroller"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<div #wrapper class=\"ag-wrapper\" tabindex=\"0\" role=\"grid\" [attr.aria-label]=\"localeText().grid\"\n [attr.aria-rowcount]=\"ariaRowCount()\" [attr.aria-colcount]=\"ariaColCount()\"\n [attr.aria-multiselectable]=\"rowSelection() === 'multi' ? 'true' : null\"\n [attr.aria-readonly]=\"readonlyGrid() ? 'true' : null\" [attr.aria-busy]=\"loading() ? 'true' : null\"\n (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\" (focusin)=\"onGridFocusIn($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu(); closeMenuBarMenu()\">\n @if (visibleMenuBarItems().length > 0 || enableQuickFilter() || showFormulaBar()) {\n <div class=\"ag-toolbar\">\n @if (visibleMenuBarItems().length > 0) {\n <agrid-menu-bar [items]=\"visibleMenuBarItems()\" [context]=\"menuBarContext()\" [label]=\"localeText().actions\"\n [openItemId]=\"openMenuBarItemId()\" (openItemIdChange)=\"onMenuBarOpenItemChange($event)\"\n (action)=\"onMenuBarAction($event)\" />\n }\n @if (enableQuickFilter()) {\n <input class=\"ag-quick-filter\" type=\"search\" [value]=\"quickFilterValue()\" (input)=\"onQuickFilterInput($event)\"\n [placeholder]=\"localeText().quickFilterPlaceholder\" [attr.aria-label]=\"localeText().quickFilterPlaceholder\" />\n }\n @if (showFormulaBar()) {\n <div class=\"ag-formula-bar\" (click)=\"$event.stopPropagation()\">\n <span class=\"ag-formula-bar-label\">{{ formulaBarLabel() || 'fx' }}</span>\n <input\n class=\"ag-formula-bar-input\"\n type=\"text\"\n [value]=\"formulaBarDraft()\"\n [disabled]=\"!selectedCell() || readonlyGrid()\"\n (focus)=\"onFormulaBarFocus()\"\n (input)=\"onFormulaBarInput($event)\"\n (change)=\"commitFormulaBar()\"\n (blur)=\"onFormulaBarBlur()\"\n (keydown)=\"onFormulaBarKeydown($event)\"\n aria-label=\"Formula bar\"\n />\n </div>\n }\n </div>\n }\n <div class=\"ag-main-area\">\n <div class=\"ag-grid-split\" [class.ag-has-right-pane]=\"hasRightPinnedPane()\">\n @if (hasPinnedPane()) {\n <div class=\"ag-pinned-pane\" [style.width.px]=\"pinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"left\"\n [headerGroups]=\"pinnedHeaderGroups()\"\n [columns]=\"pinnedHeaderColumns()\"\n [gridTemplateColumns]=\"pinnedGridTemplateColumns()\"\n [paneWidth]=\"pinnedPaneWidth()\"\n [totalWidth]=\"pinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #leftRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\" [attr.data-control]=\"true\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isPinnedPaneRowSelected(item)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? pinnedGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell\" role=\"rowheader\" aria-colindex=\"1\"\n [class.ag-control-cell--reorder]=\"allowRowReorder()\"\n [class.ag-control-cell--marking]=\"enableRowMarking()\"\n [class.ag-control-cell--numbered]=\"showRowNumbers()\"\n (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\"\n (click)=\"onControlCellClick($event, item.originalIndex)\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\">\n @if (showRowNumbers()) {\n <span class=\"ag-row-number\">{{ rowNumbers().get(item.originalIndex) }}</span>\n }\n @if (canToggleDetail(item)) {\n <button class=\"ag-detail-toggle\" type=\"button\"\n [class.ag-detail-toggle--expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-label]=\"localeText().toggleDetail\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"onDetailToggle(item.originalIndex); $event.stopPropagation()\">\u25B6</button>\n }\n @if (enableRowMarking()) {\n <input class=\"ag-row-marker\" type=\"checkbox\" [checked]=\"isRowMarked(item.originalIndex)\"\n [attr.aria-label]=\"localeText().markRow\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\" (change)=\"toggleRowMarked(item.originalIndex)\" />\n }\n </div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"pinnedColDefs()\" [paneHasSpans]=\"pinnedPaneHasSpans()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell ag-control-cell--reorder ag-ghost-handle\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\">\n @if (showControlColumn()) {\n <div class=\"ag-footer-cell ag-footer-cell--control\" role=\"gridcell\" aria-colindex=\"1\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-last]=\"bc.lastPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"ag-scroll-pane\">\n <div #horizontalScroller class=\"ag-horizontal-scroll\" (scroll)=\"onHorizontalScroll()\">\n <agrid-pane-header\n variant=\"center\"\n [headerGroups]=\"scrollableHeaderGroups()\"\n [columns]=\"scrollableHeaderColumns()\"\n [gridTemplateColumns]=\"scrollableGridTemplateColumns()\"\n [paneWidth]=\"scrollableTotalWidth()\"\n [totalWidth]=\"scrollableTotalWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #bodyRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? scrollableGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (columnWindow().leftWidth > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'1 / span ' + columnWindow().start\"></div>\n }\n @for (bc of virtualScrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"scrollableColDefs()\" [paneHasSpans]=\"scrollablePaneHasSpans()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\"\n (startEdit)=\"onStartEdit(item.originalIndex, ci)\" (draftChange)=\"onDraftChange($event)\"\n (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\" (treeToggle)=\"onTreeToggle(item)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n @if (columnWindowRightSpan() > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'span ' + columnWindowRightSpan()\"></div>\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-add-row-label\" (click)=\"onActivateAddRow()\">\n <span class=\"ag-add-row-icon\">+</span> {{ localeText().addRow }}\n </div>\n } @else if (item === 'ghost') {\n @for (bc of scrollableBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell\" [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else if (isDetailRowItem(item)) {\n <div class=\"ag-detail-panel\" [style.height.px]=\"detailRowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n <div [innerHTML]=\"detailHtml(item)\"></div>\n @if (detailColumn(); as detailCol) {\n <div class=\"ag-detail-column-field\">\n <span class=\"ag-detail-column-label\">{{ detailCol.header }}</span>\n @if (detailActions().length && isDetailFieldEditable(item)) {\n <div class=\"ag-detail-action-bar\" role=\"toolbar\" [attr.aria-label]=\"detailCol.header + localeText().templates\">\n @for (action of detailActions(); track action.id) {\n <button type=\"button\" class=\"ag-detail-action-btn\"\n (click)=\"applyDetailAction(item, action, $event)\">{{ action.label }}</button>\n }\n </div>\n }\n @if (detailEditingRow() === item.detailFor) {\n <textarea class=\"ag-detail-column-textarea\" [attr.data-detail-row]=\"item.detailFor\"\n [class.ag-detail-column-textarea--invalid]=\"!!detailValidationError()\"\n [value]=\"detailDraft()\" (input)=\"onDetailDraftInput($event)\"\n (pointerdown)=\"$event.stopPropagation()\"\n (keydown)=\"onDetailEditorKeydown(item, $event)\"\n (blur)=\"commitDetailFieldEdit(item)\"></textarea>\n @if (detailValidationError(); as message) {\n <span class=\"ag-detail-column-error\" role=\"alert\">{{ message }}</span>\n }\n } @else {\n <div class=\"ag-detail-column-value\" [class.ag-detail-column-value--editable]=\"isDetailFieldEditable(item)\"\n [attr.tabindex]=\"isDetailFieldEditable(item) ? 0 : null\"\n (click)=\"startDetailFieldEdit(item, $event)\"\n (keydown.enter)=\"startDetailFieldEdit(item, $event)\">{{ detailFieldDisplay(item) }}</div>\n }\n </div>\n }\n </div>\n } @else if (isPathTreeNodeItem(item)) {\n <div class=\"ag-path-tree-content\" [style.min-width.px]=\"scrollableTotalWidth()\"\n [style.padding-left.px]=\"treeRowLevel(item) * 16 + 8\"\n (click)=\"onTreeNodeClick(item); $event.stopPropagation()\"\n (dblclick)=\"onTreeNodeDoubleClick(item); $event.stopPropagation()\">\n <button type=\"button\" class=\"ag-tree-twisty\" [class.ag-tree-twisty--expanded]=\"treeRowExpanded(item)\"\n [attr.aria-expanded]=\"treeRowExpanded(item)\"\n (click)=\"onTreeToggle(item); $event.stopPropagation()\">\u25B6</button>\n <span>{{ pathTreeLabel(item) }}</span>\n @if (item.aggregates; as aggregates) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (col.field !== treeConfig()!.treeField && aggregates[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggregates[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n } @else {\n <div class=\"ag-group-header-content\" [style.min-width.px]=\"scrollableTotalWidth()\">\n <div class=\"ag-group-header-main\"\n (click)=\"onGroupHeaderClick(item.groupLabel); $event.stopPropagation()\">\n <span class=\"ag-group-icon\" [class.ag-group-icon--expanded]=\"!item.collapsed\">\u25B6</span>\n <span class=\"ag-group-label\">{{ item.groupLabel }}</span>\n @if (groupActions().length > 0) {\n <button class=\"ag-group-actions-btn\" [title]=\"localeText().actions\"\n (click)=\"openGroupActionsMenu($event, item.groupLabel)\">\u22EE</button>\n }\n <span class=\"ag-group-count\">{{ item.count }}</span>\n @if (getGroupDescription(item.groupLabel); as desc) {\n <span class=\"ag-group-description\">{{ desc }}</span>\n }\n @if (item.aggregates; as aggs) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (hasAggregate(col) && aggs[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggs[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n </div>\n }\n @if (isDataRowItem(item) && isRowPendingDelete(item.originalIndex)) {\n <div class=\"ag-delete-confirmation\" role=\"alertdialog\" [attr.aria-label]=\"localeText().confirmDeleteRow\"\n [style.left.px]=\"deleteConfirmationLeft()\" [style.width.px]=\"deleteConfirmationWidth() || null\"\n (pointerdown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <span class=\"ag-delete-confirmation-text\">{{ localeText().confirmDeleteRow }}</span>\n <button class=\"ag-delete-confirmation-btn ag-delete-confirmation-btn--yes\" type=\"button\"\n (click)=\"confirmPendingRowDelete()\">{{ localeText().confirmYes }}</button>\n <button class=\"ag-delete-confirmation-btn\" type=\"button\" data-delete-confirm-no\n (click)=\"cancelRowDelete()\">{{ localeText().confirmNo }}</button>\n </div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (bc of scrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (hasRightPinnedPane()) {\n <div class=\"ag-pinned-pane ag-pinned-pane--right\" [style.width.px]=\"rightPinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"right\"\n [headerGroups]=\"rightHeaderGroups()\"\n [columns]=\"rightHeaderColumns()\"\n [gridTemplateColumns]=\"rightGridTemplateColumns()\"\n [paneWidth]=\"rightPinnedPaneWidth()\"\n [totalWidth]=\"rightPinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #rightRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(item)\"\n [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"rightPinnedColDefs()\" [paneHasSpans]=\"rightPaneHasSpans()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\" [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--pinned]=\"true\" [class.ag-cell--pinned-first]=\"bc.firstRightPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (bc of rightBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-first]=\"bc.firstRightPinned\">{{ getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [agridVariableRowSize]=\"itemSizes()\" [style.width.px]=\"rightPinnedPaneWidth()\"\n (scroll)=\"onRightPinnedBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-first]=\"bc.firstRightPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (loading()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ localeText().loading }}</div>\n } @else if (isEmpty()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ emptyTextLabel() }}</div>\n }\n\n @if (showSidebar()) {\n <agrid-sidebar [open]=\"sidebarOpen()\" [activeTab]=\"sidebarTab()\" [columns]=\"colDefs()\"\n [pivotColumns]=\"sidebarPivotColumns()\" [pivotConfig]=\"provider().pivotConfig\" [headerGroups]=\"headerGroups()\"\n [row]=\"sidebarRow()\" [rowIndex]=\"selectedRowIndex()\" [hiddenColumns]=\"sidebarHiddenColumns()\" [locale]=\"locale()\"\n [localeText]=\"localeText()\" [readonlyGrid]=\"readonlyGrid()\" [useSidebarEditor]=\"useSidebarEditor()\"\n [isCellEditable]=\"isCellEditableForRow\" [errors]=\"sidebarValidationErrors()\" (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\" (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (toggleColumnGroup)=\"onSidebarToggleColumnGroup($event.fields, $event.visible)\"\n (pivotChange)=\"onSidebarPivotChange($event)\" (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\" />\n }\n </div><!-- /.ag-main-area -->\n\n @if (!hideGridStatusBar() && selectionSummaryDisplay(); as summary) {\n <div class=\"ag-status-bar\" role=\"status\" aria-live=\"polite\">\n <span><strong>{{ localeText().aggregateCount }}:</strong> {{ summary.count }}</span>\n <span><strong>{{ localeText().aggregateSum }}:</strong> {{ summary.sum }}</span>\n <span><strong>{{ localeText().aggregateAvg }}:</strong> {{ summary.average }}</span>\n <span><strong>{{ localeText().aggregateMin }}:</strong> {{ summary.min }}</span>\n <span><strong>{{ localeText().aggregateMax }}:</strong> {{ summary.max }}</span>\n </div>\n }\n\n @if (showPagination()) {\n <nav class=\"ag-pagination\" [attr.aria-label]=\"localeText().pagination\">\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().firstPage\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToPrevPage()\">\u2039</button>\n <span class=\"ag-page-info\" aria-live=\"polite\">{{ control()!.currentPage() }} / {{ totalPages() }}</span>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().next\" (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\" (click)=\"goToLastPage()\">\u00BB</button>\n <span class=\"ag-page-count\">{{ localeText().rows(filteredRowCount()) }}</span>\n </nav>\n }\n\n @if (findOpen()) {\n <agrid-find-panel [query]=\"findQuery()\" [matchCount]=\"findMatches().length\" [activeIndex]=\"findActiveIndex()\"\n [localeText]=\"localeText()\" (queryChange)=\"onFindInput($event)\" (previous)=\"goToFindMatch(-1)\"\n (next)=\"goToFindMatch(1)\" (close)=\"closeFind()\" />\n }\n\n <!-- Row context menu -->\n @if (contextMenu(); as menu) {\n @if(hasContextMenuEntries()) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @if (!treeConfig()) {\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n }\n @if (!readonlyGrid()) {\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n }\n </div>\n }\n }\n\n <!-- Cell context menu -->\n @if (cellContextMenuState(); as menu) {\n @let col = getColDef(menu.field)!;\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyCellToClipboard(menu.rowIndex, col)\">{{\n localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.rowIndex)\">{{ localeText().copyRow\n }}</button>\n @if (!treeConfig()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n }\n @if (allowAddRows() && !readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex)\">{{ localeText().insertRowAbove\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{\n localeText().insertRowBelow }}</button>\n }\n @if (!readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">{{\n localeText().deleteRow }}</button>\n }\n @if (cellMenuItems().length) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @for (item of cellMenuItems(); track $index) {\n @if (item === null) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" [class.ag-context-item--danger]=\"item.danger\"\n [disabled]=\"item.disabled\" (click)=\"runCellMenuItem(item, menu)\">{{\n item.label }}</button>\n }\n }\n }\n </div>\n }\n\n <!-- Group actions menu -->\n @if (groupActionsMenu(); as menu) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @for (action of groupActions(); track action.label) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onGroupAction(action, menu.label)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <!-- Filter dropdown -->\n @if (filterMenu(); as menu) {\n <agrid-column-menu [x]=\"menu.x\" [y]=\"menu.y\" [header]=\"getColDef(menu.field)?.header ?? menu.field\"\n [sortDir]=\"getSort(menu.field)\" [sortable]=\"menu.mode === 'column' && sortOption() !== 'none'\"\n [showColumnActions]=\"menu.mode === 'column' && !!control()\"\n [showAggregationActions]=\"menu.mode === 'column' && pivotRowColumnField()===null\"\n [pinned]=\"getColumnPinState(menu.field)\" [groupable]=\"menu.mode === 'column' && !!getColDef(menu.field)?.groupable\"\n [grouped]=\"isGroupedByField(menu.field)\" [filterable]=\"!!getColDef(menu.field)?.filterable\"\n [column]=\"getColDef(menu.field) ?? null\" [control]=\"control()\" [filter]=\"getColumnFilter(menu.field)\"\n [showFilterActions]=\"menu.mode === 'column'\"\n [showValueFilter]=\"menu.mode === 'column' && (!serverSideFiltering() || !!getColDef(menu.field)?.values?.length)\"\n [filterType]=\"getMenuFilterType(menu.field)\" [operator]=\"getMenuOperator(menu.field)\"\n [operand]=\"getMenuOperand(menu.field)\" [operand2]=\"getMenuOperand2(menu.field)\"\n (operatorChange)=\"onMenuOperatorChange(menu.field, $event)\"\n (operandChange)=\"onMenuOperandChange(menu.field, $event)\"\n (operand2Change)=\"onMenuOperand2Change(menu.field, $event)\" [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\" [valueItems]=\"(serverSideFiltering() && !getColDef(menu.field)?.values?.length)\n || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\" [localeText]=\"localeText()\"\n [sortPriority]=\"getSortPriority(menu.field)\" [hasMultiSort]=\"hasMultiSort()\" (sort)=\"onMenuSort(menu.field, $event)\"\n (resetSort)=\"onMenuResetSort(menu.field, $event)\" (autosize)=\"onMenuAutosizeColumn(menu.field)\"\n (togglePin)=\"onMenuTogglePin(menu.field)\" (togglePinRight)=\"onMenuTogglePinRight(menu.field)\"\n (hide)=\"onMenuHideColumn(menu.field)\" (toggleGroup)=\"onMenuToggleGroupBy(menu.field)\"\n (clearFilter)=\"onMenuClearFilter(menu.field)\" (clearAll)=\"onMenuClearAll()\"\n (searchChange)=\"onFilterMenuSearch($event)\" (toggleAll)=\"onMenuToggleAll(menu.field)\"\n (toggleValue)=\"onMenuToggleValue(menu.field, $event)\" [aggregate]=\"getEffectiveAggregate(getColDef(menu.field)!)\"\n (filterReplace)=\"onMenuReplaceFilter(menu.field, $event)\" (close)=\"closeOpenMenus()\"\n [customItems]=\"menu.mode === 'column' ? getColDef(menu.field)?.headerMenuItems ?? [] : []\"\n (customAction)=\"onColumnHeaderAction(menu.field, $event)\"\n (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\n }\n\n @if (columnDragPreview(); as preview) {\n <div class=\"ag-column-drag-preview\" [style.left.px]=\"preview.x\" [style.top.px]=\"preview.y\"\n [style.width.px]=\"preview.width\" [style.height.px]=\"preview.height\">\n <span>{{ preview.label }}</span>\n </div>\n }\n</div>\n", styles: ["@layer agrid-defaults{:host{--agrid-color-text: #24292f;--agrid-color-text-muted: #57606a;--agrid-color-accent: #1a73e8;--agrid-color-accent-subtle: #e8f0fe;--agrid-color-accent-fg: #1558b0;--agrid-color-accent-border: #c8d8f8;--agrid-color-danger: #d1242f;--agrid-color-danger-subtle: #fff1f0;--agrid-color-border: #d0d7de;--agrid-color-bg: #ffffff;--agrid-color-bg-subtle: #fafbfc;--agrid-color-bg-muted: #f6f8fa;--agrid-color-shadow: rgba(140, 149, 159, .2);--agrid-color-bg-stripe: #f0f2f5;--agrid-color-cell-changed: #f59e0b;--agrid-color-row-marked: #fff8c5;--agrid-color-column-marked: #e8f0fe;--agrid-color-menu-bg: #ffffff}}:host{display:flex;flex-direction:column;min-width:0;max-width:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--agrid-color-text)}.ag-wrapper{position:relative;display:flex;flex-direction:column;flex:1;min-width:0;min-height:0;border:1px solid var(--agrid-color-border);overflow:hidden;outline:none;border-radius:4px}.ag-state-overlay{position:absolute;inset:34px 0 0;display:flex;align-items:center;justify-content:center;color:var(--agrid-color-text-muted);background:color-mix(in srgb,var(--agrid-color-bg) 78%,transparent);pointer-events:none;z-index:3}.ag-status-bar{display:flex;flex-shrink:0;align-items:center;justify-content:flex-end;gap:16px;min-height:28px;padding:3px 10px;box-sizing:border-box;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);color:var(--agrid-color-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.ag-status-bar strong{color:var(--agrid-color-text);font-weight:600}@media(max-width:640px){.ag-status-bar{justify-content:flex-start;gap:10px;overflow-x:auto}.ag-status-bar span{white-space:nowrap}}.ag-row>agrid-cell,.ag-ghost-cell,.ag-footer-cell{transition:transform .16s cubic-bezier(.2,0,0,1),opacity .1s ease;will-change:transform}.ag-virtual-col-spacer{pointer-events:none}.ag-loading-row{grid-column:1 / -1;display:flex;align-items:center;padding:0 10px;box-sizing:border-box;border-bottom:1px solid var(--agrid-color-border)}.ag-loading-row span{width:min(220px,55%);height:8px;border-radius:999px;background:color-mix(in srgb,var(--agrid-color-text-muted) 18%,transparent)}.ag-column-reorder-item--dragging{opacity:.12}.ag-column-drag-preview{position:fixed;z-index:1000;display:flex;align-items:flex-start;padding:8px 10px;border:1px solid var(--agrid-color-accent);border-radius:5px;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-bg) 94%,var(--agrid-color-accent));box-shadow:0 10px 28px var(--agrid-color-shadow);font-weight:600;line-height:16px;box-sizing:border-box;pointer-events:none;opacity:.96}.ag-main-area{display:flex;flex:1;min-height:0;overflow:hidden}.ag-grid-split{display:flex;flex:1;min-width:0;min-height:0;overflow:hidden}.ag-pinned-pane{flex-shrink:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-scroll-pane{flex:1;min-width:0;min-height:0;display:flex}.ag-horizontal-scroll{flex:1;min-width:0;min-height:0;overflow-x:auto;overflow-y:hidden;display:flex;flex-direction:column}.ag-body{flex:1;overflow-x:clip;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-horizontal-scroll{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-body::-webkit-scrollbar,.ag-horizontal-scroll::-webkit-scrollbar{width:8px;height:8px}.ag-body::-webkit-scrollbar-track,.ag-horizontal-scroll::-webkit-scrollbar-track{background:transparent}.ag-body::-webkit-scrollbar-thumb,.ag-horizontal-scroll::-webkit-scrollbar-thumb{background:#0000002e;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-body::-webkit-scrollbar-thumb:hover,.ag-horizontal-scroll::-webkit-scrollbar-thumb:hover{background:#00000052;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-pinned-body{overflow:hidden}.ag-right-pinned-body{overflow-y:auto}.ag-has-right-pane .ag-body:not(.ag-pinned-body){scrollbar-width:none}.ag-has-right-pane .ag-body:not(.ag-pinned-body)::-webkit-scrollbar{display:none}.ag-row{display:grid;position:relative;--agrid-row-indication-duration: 1s}.ag-row--pending-delete>:not(.ag-delete-confirmation){opacity:.2;pointer-events:none;transition:opacity .14s ease}.ag-delete-confirmation{position:absolute;top:0;bottom:0;z-index:7;display:flex;align-items:center;justify-content:center;gap:8px;min-width:min(100%,320px);padding:2px 12px;box-sizing:border-box;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-danger-subtle) 88%,transparent);border-block:1px solid color-mix(in srgb,var(--agrid-color-danger) 35%,transparent)}.ag-delete-confirmation-text{font-weight:600;white-space:nowrap}.ag-delete-confirmation-btn{min-width:42px;padding:3px 9px;border:1px solid var(--agrid-color-border);border-radius:4px;color:var(--agrid-color-text);background:var(--agrid-color-bg);font:inherit;cursor:pointer}.ag-delete-confirmation-btn:hover,.ag-delete-confirmation-btn:focus-visible{border-color:var(--agrid-color-accent);outline:none}.ag-delete-confirmation-btn--yes{color:#fff;border-color:var(--agrid-color-danger);background:var(--agrid-color-danger)}.ag-delete-confirmation-btn--yes:hover,.ag-delete-confirmation-btn--yes:focus-visible{border-color:color-mix(in srgb,var(--agrid-color-danger) 75%,#000);background:color-mix(in srgb,var(--agrid-color-danger) 85%,#000)}:host(.ag-zebra) .ag-row--odd agrid-cell:not(.editing){background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-control-cell{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd:hover .ag-control-cell{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned-first{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned-first{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned-first{background:var(--agrid-color-accent-subtle)}.ag-row:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}.ag-row--marked agrid-cell:not(.editing),.ag-row--marked .ag-control-cell{background:var(--agrid-color-row-marked)}.ag-row--marked{box-shadow:inset 3px 0 #bf8700}.ag-row--indicating:after{content:\"\";position:absolute;inset:0;z-index:6;pointer-events:none;background:var(--agrid-row-indication-color);animation:ag-row-indication-fade var(--agrid-row-indication-duration) ease-out forwards}@keyframes ag-row-indication-fade{0%{opacity:.35}to{opacity:0}}.ag-row agrid-cell.ag-column--marked:not(.editing),.ag-footer-cell.ag-column--marked{background:var(--agrid-color-column-marked)}.ag-row--selected.ag-row--marked{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--range-selected:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent-border)}.ag-row agrid-cell.ag-cell--find-match:not(.editing){background:#fff7cc}.ag-row agrid-cell.ag-cell--find-active:not(.editing){background:#ffe58a;box-shadow:inset 0 0 0 2px #b7791f}.ag-row agrid-cell.ag-cell--range-selected.selected:not(.editing){box-shadow:inset 0 0 0 2px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-preview:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing){position:relative}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing):after{content:\"\";position:absolute;right:1px;bottom:1px;width:6px;height:6px;background:var(--agrid-color-accent);border:1px solid var(--agrid-color-bg);box-sizing:border-box;cursor:crosshair;z-index:4}.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}.ag-row--selected{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-control-cell{z-index:2;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);cursor:context-menu;display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;flex-direction:row-reverse}.ag-control-cell:after{content:\"\\22ee\";font-size:11px;color:var(--agrid-color-border);line-height:1}.ag-control-cell:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder{cursor:grab}.ag-control-cell--marking:not(.ag-control-cell--reorder){cursor:pointer}.ag-control-cell--reorder:after{content:\"\\283f\";font-size:13px;color:var(--agrid-color-text)}.ag-control-cell--reorder:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--numbered:after{content:none}.ag-control-cell--reorder:active{cursor:grabbing}.ag-row-number{min-width:0;color:var(--agrid-color-text-muted);font-size:11px;font-variant-numeric:tabular-nums;line-height:1;overflow:hidden;text-align:center;text-overflow:ellipsis;-webkit-user-select:none;user-select:none;white-space:nowrap}.ag-row-marker{position:relative;z-index:1;width:14px;height:14px;margin:0;accent-color:var(--agrid-color-accent);cursor:pointer}.ag-ghost-row{background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1.5px var(--agrid-color-accent);pointer-events:none;animation:ag-ghost-in .1s ease}@keyframes ag-ghost-in{0%{opacity:0}to{opacity:1}}.ag-ghost-handle:after{color:var(--agrid-color-accent)!important}.ag-ghost-cell{display:flex;align-items:center;padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;border-right:1px solid var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-size:13px;box-sizing:border-box;-webkit-user-select:none;user-select:none}.ag-ghost-cell:last-child{border-right:none}.ag-pinned-row-spacer,.ag-pinned-group-spacer{height:100%;border-bottom:1px solid var(--agrid-color-border);box-sizing:border-box}.ag-pinned-group-spacer{background:var(--agrid-color-bg-muted)}.ag-context-menu{position:fixed;z-index:1000;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:160px;padding:4px 0;font-size:13px}.ag-context-item{display:block;width:100%;padding:6px 16px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit}.ag-context-item:hover{background:var(--agrid-color-bg-muted)}.ag-context-separator{height:1px;background:var(--agrid-color-border);margin:3px 0}.ag-context-item--danger{color:var(--agrid-color-danger)}.ag-context-item--danger:hover{background:var(--agrid-color-danger-subtle)}.ag-group-header-row{display:flex;align-items:stretch;background:var(--agrid-color-bg-muted);border-bottom:1px solid var(--agrid-color-border);overflow:hidden}.ag-path-tree-content{display:flex;align-items:center;gap:4px;height:100%;box-sizing:border-box;color:var(--agrid-color-text);font-weight:600;border-bottom:1px solid var(--agrid-color-border)}.ag-path-tree-content .ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;color:inherit;background:transparent;cursor:pointer;font-size:10px;transition:transform .12s ease}.ag-path-tree-content .ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-group-header-content{display:flex;align-items:stretch;height:100%;width:100%;-webkit-user-select:none;user-select:none}.ag-group-header-main{display:flex;align-items:center;gap:6px;padding:0 10px;flex:1;min-width:0;cursor:pointer}.ag-group-header-main:hover{background:var(--agrid-color-bg-subtle)}.ag-group-description{font-size:11px;color:var(--agrid-color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-group-actions-btn{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border:none;background:none;border-radius:3px;cursor:pointer;color:var(--agrid-color-text-muted);font-size:14px;padding:0}.ag-group-actions-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text)}.ag-group-icon{font-size:9px;color:var(--agrid-color-text-muted);line-height:1;display:inline-block;transition:transform .15s ease}.ag-group-icon--expanded{transform:rotate(90deg)}.ag-group-label{font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-group-count{font-size:11px;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);border:1px solid var(--agrid-color-border);border-radius:10px;padding:0 7px;line-height:16px}.ag-group-aggregates{display:inline-flex;align-items:center;gap:10px;margin-left:4px;flex-wrap:wrap}.ag-group-aggregate{font-size:11px;color:var(--agrid-color-text);white-space:nowrap}.ag-group-aggregate-col{color:var(--agrid-color-text-muted);margin-right:4px}.ag-group-aggregate-op{color:var(--agrid-color-text-muted);margin-right:3px}.ag-footer{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-top:2px solid var(--agrid-color-border)}.ag-footer-cell{display:flex;align-items:center;gap:4px;padding:0 6px;height:30px;border-right:1px solid var(--agrid-color-border);box-sizing:border-box;overflow:hidden;white-space:nowrap;font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-footer-cell:last-child{border-right:none}.ag-footer-cell--control{background:var(--agrid-color-bg-subtle);border-right:1px solid var(--agrid-color-border)}.ag-footer-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-footer-label{font-size:10px;font-weight:400;color:var(--agrid-color-text-muted);flex-shrink:0}.ag-pagination{display:flex;align-items:center;gap:4px;padding:0 10px;height:34px;flex-shrink:0;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted);font-size:12px;color:var(--agrid-color-text-muted)}.ag-page-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;border:1px solid var(--agrid-color-border);border-radius:3px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;cursor:pointer;padding:0;line-height:1}.ag-page-btn:hover:not(:disabled){background:var(--agrid-color-bg-muted);border-color:var(--agrid-color-text-muted)}.ag-page-btn:disabled{opacity:.35;cursor:default}.ag-page-info{padding:0 6px;font-weight:500;color:var(--agrid-color-text);min-width:48px;text-align:center}.ag-page-count{margin-left:auto;color:var(--agrid-color-text-muted)}.ag-add-row{border-bottom:1px dashed var(--agrid-color-border);color:var(--agrid-color-text-muted);cursor:pointer}.ag-add-row:hover .ag-add-row-label{background:var(--agrid-color-bg-muted)}.ag-add-row--selected .ag-add-row-label{outline:2px solid var(--agrid-color-accent);outline-offset:-2px}.ag-add-row-label{display:flex;align-items:center;gap:4px;height:100%;padding:0 6px;font-size:12px;-webkit-user-select:none;user-select:none}.ag-add-row-icon{font-size:16px;line-height:1;color:var(--agrid-color-text-muted)}.ag-pinned-pane--right{border-left:1px solid var(--agrid-color-border);border-right:none;box-shadow:-3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned{background:var(--agrid-color-bg)}.ag-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned-first{box-shadow:none}.ag-row:hover .ag-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-row--selected .ag-cell--pinned,.ag-row .ag-cell--pinned.ag-cell--range-selected,.ag-row .ag-cell--pinned.ag-cell--fill-preview{background:var(--agrid-color-accent-subtle)}.ag-row .ag-cell--pinned.ag-cell--find-match{background:#fff7cc}.ag-row .ag-cell--pinned.ag-cell--find-active{background:#ffe58a}.ag-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;padding:6px 8px;border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle)}.ag-quick-filter{margin-left:auto;width:100%;max-width:260px;height:30px;padding:0 10px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text)}.ag-quick-filter:focus{border-color:var(--agrid-color-accent-border)}.ag-formula-bar{display:flex;align-items:center;flex:1 1 360px;min-width:220px;height:30px;border:1px solid var(--agrid-color-border);border-radius:4px;overflow:hidden;background:var(--agrid-color-bg)}.ag-formula-bar-label{display:inline-flex;align-items:center;justify-content:center;flex:0 0 74px;height:100%;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted);color:var(--agrid-color-text-muted);font-size:12px;font-weight:650;font-variant-numeric:tabular-nums}.ag-formula-bar-input{flex:1 1 auto;min-width:0;height:100%;border:0;outline:0;padding:0 9px;box-sizing:border-box;background:transparent;color:var(--agrid-color-text);font:inherit;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace}.ag-formula-bar-input:disabled{color:var(--agrid-color-text-muted);cursor:not-allowed}.ag-formula-bar:focus-within{border-color:var(--agrid-color-accent-border)}.ag-detail-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;font-size:9px;line-height:1;color:var(--agrid-color-text-muted);transition:transform .12s ease,color .12s ease}.ag-detail-toggle:hover{color:var(--agrid-color-text)}.ag-detail-toggle--expanded{transform:rotate(90deg)}.ag-detail-row{display:block;position:relative;box-sizing:border-box}.ag-detail-panel{box-sizing:border-box;height:100%;overflow:auto;padding:8px 12px;background:var(--agrid-color-bg-subtle);border-bottom:1px solid var(--agrid-color-border)}.ag-detail-column-field{display:grid;gap:4px;margin-top:10px}.ag-detail-column-label{color:var(--agrid-color-text-muted);font-size:10px;font-weight:600;letter-spacing:.4px;text-transform:uppercase}.ag-detail-action-bar{display:flex;flex-wrap:wrap;gap:6px}.ag-detail-action-btn{border:1px solid var(--agrid-color-border);border-radius:3px;padding:4px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:12px;line-height:1.3;cursor:pointer}.ag-detail-action-btn:hover,.ag-detail-action-btn:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-value,.ag-detail-column-textarea{min-height:54px;box-sizing:border-box;border:1px solid var(--agrid-color-border);border-radius:3px;padding:7px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;line-height:1.4;white-space:pre-wrap}.ag-detail-column-value--editable{cursor:text}.ag-detail-column-value--editable:hover,.ag-detail-column-value--editable:focus,.ag-detail-column-textarea:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-textarea{width:100%;height:120px;resize:vertical;user-select:text;-webkit-user-select:text;cursor:text}.ag-detail-column-textarea--invalid{border-color:var(--agrid-color-danger)}.ag-detail-column-error{color:var(--agrid-color-danger);font-size:12px}.ag-pinned-rows{position:relative;z-index:3;flex:none;background:var(--agrid-color-bg)}.ag-pinned-rows--top{box-shadow:0 2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows--bottom{box-shadow:0 -2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows .ag-row{background:var(--agrid-color-bg-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: AgridVariableRowSizeDirective, selector: "cdk-virtual-scroll-viewport[agridVariableRowSize]", inputs: ["agridVariableRowSize"] }, { kind: "component", type: AgridCellComponent, selector: "agrid-cell", inputs: ["localeText", "col", "paneColumns", "paneHasSpans", "rowIndex", "colIndex", "value", "displayValueOverride", "row", "locale", "selected", "editing", "editable", "showInfoIcon", "error", "treeCell", "treeLevel", "treeExpandable", "treeExpanded", "seedChar", "selectTextOnEdit"], outputs: ["treeToggle", "activate", "startEdit", "booleanToggle", "infoClick", "draftChange", "editorCommit", "editorCancel"] }, { kind: "component", type: AgridPaneHeaderComponent, selector: "agrid-pane-header", inputs: ["variant", "headerGroups", "columns", "gridTemplateColumns", "paneWidth", "totalWidth", "hasHeaderGroups", "hasFilterableColumns", "headerRowCount", "showControlColumn", "localeText", "pivotHeaderLabel", "pivotRowColumnField", "hasMultiSort", "filterMenuField", "markedColumnFields"], outputs: ["headerGroupPointerDown", "colHeaderPointerDown", "colHeaderClick", "filterMenuOpen", "filterConditionMenuOpen", "textFilterChange", "resizeKeyDown", "resizeStart", "autosizeColumn"] }, { kind: "component", type: AgridMenuBarComponent, selector: "agrid-menu-bar", inputs: ["items", "context", "label", "openItemId"], outputs: ["action", "openItemIdChange"] }, { kind: "component", type: AgridColumnMenuComponent, selector: "agrid-column-menu", inputs: ["localeText", "x", "y", "header", "sortDir", "sortable", "showColumnActions", "showAggregationActions", "customItems", "pinned", "groupable", "grouped", "filterable", "column", "control", "filter", "showFilterActions", "showValueFilter", "filterType", "operator", "operand", "operand2", "search", "allSelected", "valueItems", "sortPriority", "hasMultiSort", "aggregate"], outputs: ["customAction", "filterReplace", "operatorChange", "operandChange", "operand2Change", "sort", "resetSort", "autosize", "togglePin", "togglePinRight", "hide", "toggleGroup", "clearFilter", "clearAll", "searchChange", "toggleAll", "toggleValue", "setAggregate", "close"] }, { kind: "component", type: AgridFindPanelComponent, selector: "agrid-find-panel", inputs: ["localeText", "query", "matchCount", "activeIndex"], outputs: ["queryChange", "next", "previous", "close"] }, { kind: "component", type: AgridSidebarComponent, selector: "agrid-sidebar", inputs: ["open", "activeTab", "columns", "pivotColumns", "pivotConfig", "headerGroups", "row", "rowIndex", "hiddenColumns", "locale", "localeText", "readonlyGrid", "useSidebarEditor", "isCellEditable", "errors"], outputs: ["close", "tabChange", "toggleColumn", "toggleColumnGroup", "detailEdit", "save", "pivotChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9578
10434
|
}
|
|
9579
10435
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridComponent, decorators: [{
|
|
9580
10436
|
type: Component,
|
|
@@ -9592,8 +10448,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
9592
10448
|
'[class.ag-zebra]': 'zebraStripes()',
|
|
9593
10449
|
'[style.min-height]': 'minHeight()',
|
|
9594
10450
|
'[style.max-height]': 'maxHeight()',
|
|
9595
|
-
}, template: "<div #wrapper class=\"ag-wrapper\" tabindex=\"0\" role=\"grid\" [attr.aria-label]=\"localeText().grid\"\n [attr.aria-rowcount]=\"ariaRowCount()\" [attr.aria-colcount]=\"ariaColCount()\"\n [attr.aria-multiselectable]=\"rowSelection() === 'multi' ? 'true' : null\"\n [attr.aria-readonly]=\"readonlyGrid() ? 'true' : null\" [attr.aria-busy]=\"loading() ? 'true' : null\"\n (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\" (focusin)=\"onGridFocusIn($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu(); closeMenuBarMenu()\">\n @if (visibleMenuBarItems().length > 0 || enableQuickFilter()) {\n <div class=\"ag-toolbar\">\n @if (visibleMenuBarItems().length > 0) {\n <agrid-menu-bar [items]=\"visibleMenuBarItems()\" [context]=\"menuBarContext()\" [label]=\"localeText().actions\"\n [openItemId]=\"openMenuBarItemId()\" (openItemIdChange)=\"onMenuBarOpenItemChange($event)\"\n (action)=\"onMenuBarAction($event)\" />\n }\n @if (enableQuickFilter()) {\n <input class=\"ag-quick-filter\" type=\"search\" [value]=\"quickFilterValue()\" (input)=\"onQuickFilterInput($event)\"\n [placeholder]=\"localeText().quickFilterPlaceholder\" [attr.aria-label]=\"localeText().quickFilterPlaceholder\" />\n }\n </div>\n }\n <div class=\"ag-main-area\">\n <div class=\"ag-grid-split\" [class.ag-has-right-pane]=\"hasRightPinnedPane()\">\n @if (hasPinnedPane()) {\n <div class=\"ag-pinned-pane\" [style.width.px]=\"pinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"left\"\n [headerGroups]=\"pinnedHeaderGroups()\"\n [columns]=\"pinnedHeaderColumns()\"\n [gridTemplateColumns]=\"pinnedGridTemplateColumns()\"\n [paneWidth]=\"pinnedPaneWidth()\"\n [totalWidth]=\"pinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #leftRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\" [attr.data-control]=\"true\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isPinnedPaneRowSelected(item)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? pinnedGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell\" role=\"rowheader\" aria-colindex=\"1\"\n [class.ag-control-cell--reorder]=\"allowRowReorder()\"\n [class.ag-control-cell--marking]=\"enableRowMarking()\"\n (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\"\n (click)=\"onControlCellClick($event, item.originalIndex)\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\">\n @if (canToggleDetail(item)) {\n <button class=\"ag-detail-toggle\" type=\"button\"\n [class.ag-detail-toggle--expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-label]=\"localeText().toggleDetail\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"onDetailToggle(item.originalIndex); $event.stopPropagation()\">\u25B6</button>\n }\n @if (enableRowMarking()) {\n <input class=\"ag-row-marker\" type=\"checkbox\" [checked]=\"isRowMarked(item.originalIndex)\"\n [attr.aria-label]=\"localeText().markRow\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\" (change)=\"toggleRowMarked(item.originalIndex)\" />\n }\n </div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"pinnedColDefs()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell ag-control-cell--reorder ag-ghost-handle\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\">\n @if (showControlColumn()) {\n <div class=\"ag-footer-cell ag-footer-cell--control\" role=\"gridcell\" aria-colindex=\"1\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-last]=\"bc.lastPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"ag-scroll-pane\">\n <div #horizontalScroller class=\"ag-horizontal-scroll\" (scroll)=\"onHorizontalScroll()\">\n <agrid-pane-header\n variant=\"center\"\n [headerGroups]=\"scrollableHeaderGroups()\"\n [columns]=\"scrollableHeaderColumns()\"\n [gridTemplateColumns]=\"scrollableGridTemplateColumns()\"\n [paneWidth]=\"scrollableTotalWidth()\"\n [totalWidth]=\"scrollableTotalWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #bodyRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? scrollableGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (columnWindow().leftWidth > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'1 / span ' + columnWindow().start\"></div>\n }\n @for (bc of virtualScrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"scrollableColDefs()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\"\n (startEdit)=\"onStartEdit(item.originalIndex, ci)\" (draftChange)=\"onDraftChange($event)\"\n (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\" (treeToggle)=\"onTreeToggle(item)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n @if (columnWindowRightSpan() > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'span ' + columnWindowRightSpan()\"></div>\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-add-row-label\" (click)=\"onActivateAddRow()\">\n <span class=\"ag-add-row-icon\">+</span> {{ localeText().addRow }}\n </div>\n } @else if (item === 'ghost') {\n @for (bc of scrollableBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell\" [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else if (isDetailRowItem(item)) {\n <div class=\"ag-detail-panel\" [style.height.px]=\"detailRowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n <div [innerHTML]=\"detailHtml(item)\"></div>\n @if (detailColumn(); as detailCol) {\n <div class=\"ag-detail-column-field\">\n <span class=\"ag-detail-column-label\">{{ detailCol.header }}</span>\n @if (detailActions().length && isDetailFieldEditable(item)) {\n <div class=\"ag-detail-action-bar\" role=\"toolbar\" [attr.aria-label]=\"detailCol.header + localeText().templates\">\n @for (action of detailActions(); track action.id) {\n <button type=\"button\" class=\"ag-detail-action-btn\"\n (click)=\"applyDetailAction(item, action, $event)\">{{ action.label }}</button>\n }\n </div>\n }\n @if (detailEditingRow() === item.detailFor) {\n <textarea class=\"ag-detail-column-textarea\" [attr.data-detail-row]=\"item.detailFor\"\n [class.ag-detail-column-textarea--invalid]=\"!!detailValidationError()\"\n [value]=\"detailDraft()\" (input)=\"onDetailDraftInput($event)\"\n (pointerdown)=\"$event.stopPropagation()\"\n (keydown)=\"onDetailEditorKeydown(item, $event)\"\n (blur)=\"commitDetailFieldEdit(item)\"></textarea>\n @if (detailValidationError(); as message) {\n <span class=\"ag-detail-column-error\" role=\"alert\">{{ message }}</span>\n }\n } @else {\n <div class=\"ag-detail-column-value\" [class.ag-detail-column-value--editable]=\"isDetailFieldEditable(item)\"\n [attr.tabindex]=\"isDetailFieldEditable(item) ? 0 : null\"\n (click)=\"startDetailFieldEdit(item, $event)\"\n (keydown.enter)=\"startDetailFieldEdit(item, $event)\">{{ detailFieldDisplay(item) }}</div>\n }\n </div>\n }\n </div>\n } @else if (isPathTreeNodeItem(item)) {\n <div class=\"ag-path-tree-content\" [style.min-width.px]=\"scrollableTotalWidth()\"\n [style.padding-left.px]=\"treeRowLevel(item) * 16 + 8\"\n (click)=\"onTreeNodeClick(item); $event.stopPropagation()\"\n (dblclick)=\"onTreeNodeDoubleClick(item); $event.stopPropagation()\">\n <button type=\"button\" class=\"ag-tree-twisty\" [class.ag-tree-twisty--expanded]=\"treeRowExpanded(item)\"\n [attr.aria-expanded]=\"treeRowExpanded(item)\"\n (click)=\"onTreeToggle(item); $event.stopPropagation()\">\u25B6</button>\n <span>{{ pathTreeLabel(item) }}</span>\n @if (item.aggregates; as aggregates) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (col.field !== treeConfig()!.treeField && aggregates[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggregates[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n } @else {\n <div class=\"ag-group-header-content\" [style.min-width.px]=\"scrollableTotalWidth()\">\n <div class=\"ag-group-header-main\"\n (click)=\"onGroupHeaderClick(item.groupLabel); $event.stopPropagation()\">\n <span class=\"ag-group-icon\" [class.ag-group-icon--expanded]=\"!item.collapsed\">\u25B6</span>\n <span class=\"ag-group-label\">{{ item.groupLabel }}</span>\n @if (groupActions().length > 0) {\n <button class=\"ag-group-actions-btn\" [title]=\"localeText().actions\"\n (click)=\"openGroupActionsMenu($event, item.groupLabel)\">\u22EE</button>\n }\n <span class=\"ag-group-count\">{{ item.count }}</span>\n @if (getGroupDescription(item.groupLabel); as desc) {\n <span class=\"ag-group-description\">{{ desc }}</span>\n }\n @if (item.aggregates; as aggs) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (hasAggregate(col) && aggs[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggs[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n </div>\n }\n @if (isDataRowItem(item) && isRowPendingDelete(item.originalIndex)) {\n <div class=\"ag-delete-confirmation\" role=\"alertdialog\" [attr.aria-label]=\"localeText().confirmDeleteRow\"\n [style.left.px]=\"deleteConfirmationLeft()\" [style.width.px]=\"deleteConfirmationWidth() || null\"\n (pointerdown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <span class=\"ag-delete-confirmation-text\">{{ localeText().confirmDeleteRow }}</span>\n <button class=\"ag-delete-confirmation-btn ag-delete-confirmation-btn--yes\" type=\"button\"\n (click)=\"confirmPendingRowDelete()\">{{ localeText().confirmYes }}</button>\n <button class=\"ag-delete-confirmation-btn\" type=\"button\" data-delete-confirm-no\n (click)=\"cancelRowDelete()\">{{ localeText().confirmNo }}</button>\n </div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (bc of scrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (hasRightPinnedPane()) {\n <div class=\"ag-pinned-pane ag-pinned-pane--right\" [style.width.px]=\"rightPinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"right\"\n [headerGroups]=\"rightHeaderGroups()\"\n [columns]=\"rightHeaderColumns()\"\n [gridTemplateColumns]=\"rightGridTemplateColumns()\"\n [paneWidth]=\"rightPinnedPaneWidth()\"\n [totalWidth]=\"rightPinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #rightRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(item)\"\n [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"rightPinnedColDefs()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\" [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--pinned]=\"true\" [class.ag-cell--pinned-first]=\"bc.firstRightPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (bc of rightBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-first]=\"bc.firstRightPinned\">{{ getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [agridVariableRowSize]=\"itemSizes()\" [style.width.px]=\"rightPinnedPaneWidth()\"\n (scroll)=\"onRightPinnedBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-first]=\"bc.firstRightPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (loading()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ localeText().loading }}</div>\n } @else if (isEmpty()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ emptyTextLabel() }}</div>\n }\n\n @if (showSidebar()) {\n <agrid-sidebar [open]=\"sidebarOpen()\" [activeTab]=\"sidebarTab()\" [columns]=\"colDefs()\"\n [pivotColumns]=\"sidebarPivotColumns()\" [pivotConfig]=\"provider().pivotConfig\" [headerGroups]=\"headerGroups()\"\n [row]=\"sidebarRow()\" [rowIndex]=\"selectedRowIndex()\" [hiddenColumns]=\"sidebarHiddenColumns()\" [locale]=\"locale()\"\n [localeText]=\"localeText()\" [readonlyGrid]=\"readonlyGrid()\" [useSidebarEditor]=\"useSidebarEditor()\"\n [isCellEditable]=\"isCellEditableForRow\" [errors]=\"sidebarValidationErrors()\" (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\" (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (toggleColumnGroup)=\"onSidebarToggleColumnGroup($event.fields, $event.visible)\"\n (pivotChange)=\"onSidebarPivotChange($event)\" (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\" />\n }\n </div><!-- /.ag-main-area -->\n\n @if (!hideGridStatusBar() && selectionSummaryDisplay(); as summary) {\n <div class=\"ag-status-bar\" role=\"status\" aria-live=\"polite\">\n <span><strong>{{ localeText().aggregateCount }}:</strong> {{ summary.count }}</span>\n <span><strong>{{ localeText().aggregateSum }}:</strong> {{ summary.sum }}</span>\n <span><strong>{{ localeText().aggregateAvg }}:</strong> {{ summary.average }}</span>\n <span><strong>{{ localeText().aggregateMin }}:</strong> {{ summary.min }}</span>\n <span><strong>{{ localeText().aggregateMax }}:</strong> {{ summary.max }}</span>\n </div>\n }\n\n @if (showPagination()) {\n <nav class=\"ag-pagination\" [attr.aria-label]=\"localeText().pagination\">\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().firstPage\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToPrevPage()\">\u2039</button>\n <span class=\"ag-page-info\" aria-live=\"polite\">{{ control()!.currentPage() }} / {{ totalPages() }}</span>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().next\" (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\" (click)=\"goToLastPage()\">\u00BB</button>\n <span class=\"ag-page-count\">{{ localeText().rows(filteredRowCount()) }}</span>\n </nav>\n }\n\n @if (findOpen()) {\n <agrid-find-panel [query]=\"findQuery()\" [matchCount]=\"findMatches().length\" [activeIndex]=\"findActiveIndex()\"\n [localeText]=\"localeText()\" (queryChange)=\"onFindInput($event)\" (previous)=\"goToFindMatch(-1)\"\n (next)=\"goToFindMatch(1)\" (close)=\"closeFind()\" />\n }\n\n <!-- Row context menu -->\n @if (contextMenu(); as menu) {\n @if(hasContextMenuEntries()) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @if (!treeConfig()) {\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n }\n @if (!readonlyGrid()) {\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n }\n </div>\n }\n }\n\n <!-- Cell context menu -->\n @if (cellContextMenuState(); as menu) {\n @let col = getColDef(menu.field)!;\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyCellToClipboard(menu.rowIndex, col)\">{{\n localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.rowIndex)\">{{ localeText().copyRow\n }}</button>\n @if (!treeConfig()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n }\n @if (allowAddRows() && !readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex)\">{{ localeText().insertRowAbove\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{\n localeText().insertRowBelow }}</button>\n }\n @if (!readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">{{\n localeText().deleteRow }}</button>\n }\n @if (cellMenuItems().length) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @for (item of cellMenuItems(); track $index) {\n @if (item === null) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" [class.ag-context-item--danger]=\"item.danger\"\n [disabled]=\"item.disabled\" (click)=\"runCellMenuItem(item, menu)\">{{\n item.label }}</button>\n }\n }\n }\n </div>\n }\n\n <!-- Group actions menu -->\n @if (groupActionsMenu(); as menu) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @for (action of groupActions(); track action.label) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onGroupAction(action, menu.label)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <!-- Filter dropdown -->\n @if (filterMenu(); as menu) {\n <agrid-column-menu [x]=\"menu.x\" [y]=\"menu.y\" [header]=\"getColDef(menu.field)?.header ?? menu.field\"\n [sortDir]=\"getSort(menu.field)\" [sortable]=\"menu.mode === 'column' && sortOption() !== 'none'\"\n [showColumnActions]=\"menu.mode === 'column' && !!control()\"\n [showAggregationActions]=\"menu.mode === 'column' && pivotRowColumnField()===null\"\n [pinned]=\"getColumnPinState(menu.field)\" [groupable]=\"menu.mode === 'column' && !!getColDef(menu.field)?.groupable\"\n [grouped]=\"isGroupedByField(menu.field)\" [filterable]=\"!!getColDef(menu.field)?.filterable\"\n [showFilterActions]=\"menu.mode === 'column'\"\n [showValueFilter]=\"menu.mode === 'column' && (!serverSideFiltering() || !!getColDef(menu.field)?.values?.length)\"\n [filterType]=\"getMenuFilterType(menu.field)\" [operator]=\"getMenuOperator(menu.field)\"\n [operand]=\"getMenuOperand(menu.field)\" [operand2]=\"getMenuOperand2(menu.field)\"\n (operatorChange)=\"onMenuOperatorChange(menu.field, $event)\"\n (operandChange)=\"onMenuOperandChange(menu.field, $event)\"\n (operand2Change)=\"onMenuOperand2Change(menu.field, $event)\" [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\" [valueItems]=\"(serverSideFiltering() && !getColDef(menu.field)?.values?.length)\n || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\" [localeText]=\"localeText()\"\n [sortPriority]=\"getSortPriority(menu.field)\" [hasMultiSort]=\"hasMultiSort()\" (sort)=\"onMenuSort(menu.field, $event)\"\n (resetSort)=\"onMenuResetSort(menu.field, $event)\" (autosize)=\"onMenuAutosizeColumn(menu.field)\"\n (togglePin)=\"onMenuTogglePin(menu.field)\" (togglePinRight)=\"onMenuTogglePinRight(menu.field)\"\n (hide)=\"onMenuHideColumn(menu.field)\" (toggleGroup)=\"onMenuToggleGroupBy(menu.field)\"\n (clearFilter)=\"onMenuClearFilter(menu.field)\" (clearAll)=\"onMenuClearAll()\"\n (searchChange)=\"onFilterMenuSearch($event)\" (toggleAll)=\"onMenuToggleAll(menu.field)\"\n (toggleValue)=\"onMenuToggleValue(menu.field, $event)\" [aggregate]=\"getEffectiveAggregate(getColDef(menu.field)!)\"\n [customItems]=\"menu.mode === 'column' ? getColDef(menu.field)?.headerMenuItems ?? [] : []\"\n (customAction)=\"onColumnHeaderAction(menu.field, $event)\"\n (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\n }\n\n @if (columnDragPreview(); as preview) {\n <div class=\"ag-column-drag-preview\" [style.left.px]=\"preview.x\" [style.top.px]=\"preview.y\"\n [style.width.px]=\"preview.width\" [style.height.px]=\"preview.height\">\n <span>{{ preview.label }}</span>\n </div>\n }\n</div>\n", styles: ["@layer agrid-defaults{:host{--agrid-color-text: #24292f;--agrid-color-text-muted: #57606a;--agrid-color-accent: #1a73e8;--agrid-color-accent-subtle: #e8f0fe;--agrid-color-accent-fg: #1558b0;--agrid-color-accent-border: #c8d8f8;--agrid-color-danger: #d1242f;--agrid-color-danger-subtle: #fff1f0;--agrid-color-border: #d0d7de;--agrid-color-bg: #ffffff;--agrid-color-bg-subtle: #fafbfc;--agrid-color-bg-muted: #f6f8fa;--agrid-color-shadow: rgba(140, 149, 159, .2);--agrid-color-bg-stripe: #f0f2f5;--agrid-color-cell-changed: #f59e0b;--agrid-color-row-marked: #fff8c5;--agrid-color-column-marked: #e8f0fe;--agrid-color-menu-bg: #ffffff}}:host{display:flex;flex-direction:column;min-height:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--agrid-color-text)}.ag-wrapper{position:relative;display:flex;flex-direction:column;flex:1;min-height:0;border:1px solid var(--agrid-color-border);overflow:hidden;outline:none;border-radius:4px}.ag-state-overlay{position:absolute;inset:34px 0 0;display:flex;align-items:center;justify-content:center;color:var(--agrid-color-text-muted);background:color-mix(in srgb,var(--agrid-color-bg) 78%,transparent);pointer-events:none;z-index:3}.ag-status-bar{display:flex;flex-shrink:0;align-items:center;justify-content:flex-end;gap:16px;min-height:28px;padding:3px 10px;box-sizing:border-box;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);color:var(--agrid-color-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.ag-status-bar strong{color:var(--agrid-color-text);font-weight:600}@media(max-width:640px){.ag-status-bar{justify-content:flex-start;gap:10px;overflow-x:auto}.ag-status-bar span{white-space:nowrap}}.ag-row>agrid-cell,.ag-ghost-cell,.ag-footer-cell{transition:transform .16s cubic-bezier(.2,0,0,1),opacity .1s ease;will-change:transform}.ag-virtual-col-spacer{pointer-events:none}.ag-loading-row{grid-column:1 / -1;display:flex;align-items:center;padding:0 10px;box-sizing:border-box;border-bottom:1px solid var(--agrid-color-border)}.ag-loading-row span{width:min(220px,55%);height:8px;border-radius:999px;background:color-mix(in srgb,var(--agrid-color-text-muted) 18%,transparent)}.ag-column-reorder-item--dragging{opacity:.12}.ag-column-drag-preview{position:fixed;z-index:1000;display:flex;align-items:flex-start;padding:8px 10px;border:1px solid var(--agrid-color-accent);border-radius:5px;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-bg) 94%,var(--agrid-color-accent));box-shadow:0 10px 28px var(--agrid-color-shadow);font-weight:600;line-height:16px;box-sizing:border-box;pointer-events:none;opacity:.96}.ag-main-area{display:flex;flex:1;min-height:0;overflow:hidden}.ag-grid-split{display:flex;flex:1;min-width:0;min-height:0;overflow:hidden}.ag-pinned-pane{flex-shrink:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-scroll-pane{flex:1;min-width:0;min-height:0;display:flex}.ag-horizontal-scroll{flex:1;min-width:0;min-height:0;overflow-x:auto;overflow-y:hidden;display:flex;flex-direction:column}.ag-body{flex:1;overflow-x:clip;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-horizontal-scroll{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-body::-webkit-scrollbar,.ag-horizontal-scroll::-webkit-scrollbar{width:8px;height:8px}.ag-body::-webkit-scrollbar-track,.ag-horizontal-scroll::-webkit-scrollbar-track{background:transparent}.ag-body::-webkit-scrollbar-thumb,.ag-horizontal-scroll::-webkit-scrollbar-thumb{background:#0000002e;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-body::-webkit-scrollbar-thumb:hover,.ag-horizontal-scroll::-webkit-scrollbar-thumb:hover{background:#00000052;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-pinned-body{overflow:hidden}.ag-right-pinned-body{overflow-y:auto}.ag-has-right-pane .ag-body:not(.ag-pinned-body){scrollbar-width:none}.ag-has-right-pane .ag-body:not(.ag-pinned-body)::-webkit-scrollbar{display:none}.ag-row{display:grid;position:relative;--agrid-row-indication-duration: 1s}.ag-row--pending-delete>:not(.ag-delete-confirmation){opacity:.2;pointer-events:none;transition:opacity .14s ease}.ag-delete-confirmation{position:absolute;top:0;bottom:0;z-index:7;display:flex;align-items:center;justify-content:center;gap:8px;min-width:min(100%,320px);padding:2px 12px;box-sizing:border-box;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-danger-subtle) 88%,transparent);border-block:1px solid color-mix(in srgb,var(--agrid-color-danger) 35%,transparent)}.ag-delete-confirmation-text{font-weight:600;white-space:nowrap}.ag-delete-confirmation-btn{min-width:42px;padding:3px 9px;border:1px solid var(--agrid-color-border);border-radius:4px;color:var(--agrid-color-text);background:var(--agrid-color-bg);font:inherit;cursor:pointer}.ag-delete-confirmation-btn:hover,.ag-delete-confirmation-btn:focus-visible{border-color:var(--agrid-color-accent);outline:none}.ag-delete-confirmation-btn--yes{color:#fff;border-color:var(--agrid-color-danger);background:var(--agrid-color-danger)}.ag-delete-confirmation-btn--yes:hover,.ag-delete-confirmation-btn--yes:focus-visible{border-color:color-mix(in srgb,var(--agrid-color-danger) 75%,#000);background:color-mix(in srgb,var(--agrid-color-danger) 85%,#000)}:host(.ag-zebra) .ag-row--odd agrid-cell:not(.editing){background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-control-cell{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd:hover .ag-control-cell{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned-first{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned-first{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned-first{background:var(--agrid-color-accent-subtle)}.ag-row:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}.ag-row--marked agrid-cell:not(.editing),.ag-row--marked .ag-control-cell{background:var(--agrid-color-row-marked)}.ag-row--marked{box-shadow:inset 3px 0 #bf8700}.ag-row--indicating:after{content:\"\";position:absolute;inset:0;z-index:6;pointer-events:none;background:var(--agrid-row-indication-color);animation:ag-row-indication-fade var(--agrid-row-indication-duration) ease-out forwards}@keyframes ag-row-indication-fade{0%{opacity:.35}to{opacity:0}}.ag-row agrid-cell.ag-column--marked:not(.editing),.ag-footer-cell.ag-column--marked{background:var(--agrid-color-column-marked)}.ag-row--selected.ag-row--marked{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--range-selected:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent-border)}.ag-row agrid-cell.ag-cell--find-match:not(.editing){background:#fff7cc}.ag-row agrid-cell.ag-cell--find-active:not(.editing){background:#ffe58a;box-shadow:inset 0 0 0 2px #b7791f}.ag-row agrid-cell.ag-cell--range-selected.selected:not(.editing){box-shadow:inset 0 0 0 2px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-preview:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing){position:relative}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing):after{content:\"\";position:absolute;right:1px;bottom:1px;width:6px;height:6px;background:var(--agrid-color-accent);border:1px solid var(--agrid-color-bg);box-sizing:border-box;cursor:crosshair;z-index:4}.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}.ag-row--selected{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-control-cell{z-index:2;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);cursor:context-menu;display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;flex-direction:row-reverse}.ag-control-cell:after{content:\"\\22ee\";font-size:11px;color:var(--agrid-color-border);line-height:1}.ag-control-cell:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder{cursor:grab}.ag-control-cell--marking:not(.ag-control-cell--reorder){cursor:pointer}.ag-control-cell--reorder:after{content:\"\\283f\";font-size:13px;color:var(--agrid-color-text)}.ag-control-cell--reorder:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder:active{cursor:grabbing}.ag-row-marker{position:relative;z-index:1;width:14px;height:14px;margin:0;accent-color:var(--agrid-color-accent);cursor:pointer}.ag-ghost-row{background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1.5px var(--agrid-color-accent);pointer-events:none;animation:ag-ghost-in .1s ease}@keyframes ag-ghost-in{0%{opacity:0}to{opacity:1}}.ag-ghost-handle:after{color:var(--agrid-color-accent)!important}.ag-ghost-cell{display:flex;align-items:center;padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;border-right:1px solid var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-size:13px;box-sizing:border-box;-webkit-user-select:none;user-select:none}.ag-ghost-cell:last-child{border-right:none}.ag-pinned-row-spacer,.ag-pinned-group-spacer{height:100%;border-bottom:1px solid var(--agrid-color-border);box-sizing:border-box}.ag-pinned-group-spacer{background:var(--agrid-color-bg-muted)}.ag-context-menu{position:fixed;z-index:1000;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:160px;padding:4px 0;font-size:13px}.ag-context-item{display:block;width:100%;padding:6px 16px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit}.ag-context-item:hover{background:var(--agrid-color-bg-muted)}.ag-context-separator{height:1px;background:var(--agrid-color-border);margin:3px 0}.ag-context-item--danger{color:var(--agrid-color-danger)}.ag-context-item--danger:hover{background:var(--agrid-color-danger-subtle)}.ag-group-header-row{display:flex;align-items:stretch;background:var(--agrid-color-bg-muted);border-bottom:1px solid var(--agrid-color-border);overflow:hidden}.ag-path-tree-content{display:flex;align-items:center;gap:4px;height:100%;box-sizing:border-box;color:var(--agrid-color-text);font-weight:600;border-bottom:1px solid var(--agrid-color-border)}.ag-path-tree-content .ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;color:inherit;background:transparent;cursor:pointer;font-size:10px;transition:transform .12s ease}.ag-path-tree-content .ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-group-header-content{display:flex;align-items:stretch;height:100%;width:100%;-webkit-user-select:none;user-select:none}.ag-group-header-main{display:flex;align-items:center;gap:6px;padding:0 10px;flex:1;min-width:0;cursor:pointer}.ag-group-header-main:hover{background:var(--agrid-color-bg-subtle)}.ag-group-description{font-size:11px;color:var(--agrid-color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-group-actions-btn{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border:none;background:none;border-radius:3px;cursor:pointer;color:var(--agrid-color-text-muted);font-size:14px;padding:0}.ag-group-actions-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text)}.ag-group-icon{font-size:9px;color:var(--agrid-color-text-muted);line-height:1;display:inline-block;transition:transform .15s ease}.ag-group-icon--expanded{transform:rotate(90deg)}.ag-group-label{font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-group-count{font-size:11px;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);border:1px solid var(--agrid-color-border);border-radius:10px;padding:0 7px;line-height:16px}.ag-group-aggregates{display:inline-flex;align-items:center;gap:10px;margin-left:4px;flex-wrap:wrap}.ag-group-aggregate{font-size:11px;color:var(--agrid-color-text);white-space:nowrap}.ag-group-aggregate-col{color:var(--agrid-color-text-muted);margin-right:4px}.ag-group-aggregate-op{color:var(--agrid-color-text-muted);margin-right:3px}.ag-footer{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-top:2px solid var(--agrid-color-border)}.ag-footer-cell{display:flex;align-items:center;gap:4px;padding:0 6px;height:30px;border-right:1px solid var(--agrid-color-border);box-sizing:border-box;overflow:hidden;white-space:nowrap;font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-footer-cell:last-child{border-right:none}.ag-footer-cell--control{background:var(--agrid-color-bg-subtle);border-right:1px solid var(--agrid-color-border)}.ag-footer-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-footer-label{font-size:10px;font-weight:400;color:var(--agrid-color-text-muted);flex-shrink:0}.ag-pagination{display:flex;align-items:center;gap:4px;padding:0 10px;height:34px;flex-shrink:0;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted);font-size:12px;color:var(--agrid-color-text-muted)}.ag-page-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;border:1px solid var(--agrid-color-border);border-radius:3px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;cursor:pointer;padding:0;line-height:1}.ag-page-btn:hover:not(:disabled){background:var(--agrid-color-bg-muted);border-color:var(--agrid-color-text-muted)}.ag-page-btn:disabled{opacity:.35;cursor:default}.ag-page-info{padding:0 6px;font-weight:500;color:var(--agrid-color-text);min-width:48px;text-align:center}.ag-page-count{margin-left:auto;color:var(--agrid-color-text-muted)}.ag-add-row{border-bottom:1px dashed var(--agrid-color-border);color:var(--agrid-color-text-muted);cursor:pointer}.ag-add-row:hover .ag-add-row-label{background:var(--agrid-color-bg-muted)}.ag-add-row--selected .ag-add-row-label{outline:2px solid var(--agrid-color-accent);outline-offset:-2px}.ag-add-row-label{display:flex;align-items:center;gap:4px;height:100%;padding:0 6px;font-size:12px;-webkit-user-select:none;user-select:none}.ag-add-row-icon{font-size:16px;line-height:1;color:var(--agrid-color-text-muted)}.ag-pinned-pane--right{border-left:1px solid var(--agrid-color-border);border-right:none;box-shadow:-3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned{background:var(--agrid-color-bg)}.ag-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned-first{box-shadow:none}.ag-row:hover .ag-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-row--selected .ag-cell--pinned,.ag-row .ag-cell--pinned.ag-cell--range-selected,.ag-row .ag-cell--pinned.ag-cell--fill-preview{background:var(--agrid-color-accent-subtle)}.ag-row .ag-cell--pinned.ag-cell--find-match{background:#fff7cc}.ag-row .ag-cell--pinned.ag-cell--find-active{background:#ffe58a}.ag-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;padding:6px 8px;border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle)}.ag-quick-filter{margin-left:auto;width:100%;max-width:260px;height:30px;padding:0 10px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text)}.ag-quick-filter:focus{border-color:var(--agrid-color-accent-border)}.ag-detail-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;font-size:9px;line-height:1;color:var(--agrid-color-text-muted);transition:transform .12s ease,color .12s ease}.ag-detail-toggle:hover{color:var(--agrid-color-text)}.ag-detail-toggle--expanded{transform:rotate(90deg)}.ag-detail-row{display:block;position:relative;box-sizing:border-box}.ag-detail-panel{box-sizing:border-box;height:100%;overflow:auto;padding:8px 12px;background:var(--agrid-color-bg-subtle);border-bottom:1px solid var(--agrid-color-border)}.ag-detail-column-field{display:grid;gap:4px;margin-top:10px}.ag-detail-column-label{color:var(--agrid-color-text-muted);font-size:10px;font-weight:600;letter-spacing:.4px;text-transform:uppercase}.ag-detail-action-bar{display:flex;flex-wrap:wrap;gap:6px}.ag-detail-action-btn{border:1px solid var(--agrid-color-border);border-radius:3px;padding:4px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:12px;line-height:1.3;cursor:pointer}.ag-detail-action-btn:hover,.ag-detail-action-btn:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-value,.ag-detail-column-textarea{min-height:54px;box-sizing:border-box;border:1px solid var(--agrid-color-border);border-radius:3px;padding:7px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;line-height:1.4;white-space:pre-wrap}.ag-detail-column-value--editable{cursor:text}.ag-detail-column-value--editable:hover,.ag-detail-column-value--editable:focus,.ag-detail-column-textarea:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-textarea{width:100%;height:120px;resize:vertical;user-select:text;-webkit-user-select:text;cursor:text}.ag-detail-column-textarea--invalid{border-color:var(--agrid-color-danger)}.ag-detail-column-error{color:var(--agrid-color-danger);font-size:12px}.ag-pinned-rows{position:relative;z-index:3;flex:none;background:var(--agrid-color-bg)}.ag-pinned-rows--top{box-shadow:0 2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows--bottom{box-shadow:0 -2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows .ag-row{background:var(--agrid-color-bg-subtle)}\n"] }]
|
|
9596
|
-
}], ctorParameters: () => [], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }], cellEdit: [{ type: i0.Output, args: ["cellEdit"] }], recordEdit: [{ type: i0.Output, args: ["recordEdit"] }], rowRemoved: [{ type: i0.Output, args: ["rowRemoved"] }], prepareAddRecord: [{ type: i0.Output, args: ["prepareAddRecord"] }], rowReorder: [{ type: i0.Output, args: ["rowReorder"] }], rowSelect: [{ type: i0.Output, args: ["rowSelect"] }], rowMark: [{ type: i0.Output, args: ["rowMark"] }], columnMark: [{ type: i0.Output, args: ["columnMark"] }], columnHeaderAction: [{ type: i0.Output, args: ["columnHeaderAction"] }], firstDataRendered: [{ type: i0.Output, args: ["firstDataRendered"] }], rowDoubleClicked: [{ type: i0.Output, args: ["rowDoubleClicked"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], treeNodeClick: [{ type: i0.Output, args: ["treeNodeClick"] }], settingsChange: [{ type: i0.Output, args: ["settingsChange"] }], treeNodeDoubleClicked: [{ type: i0.Output, args: ["treeNodeDoubleClicked"] }], rowChanged: [{ type: i0.Output, args: ["rowChanged"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], quickFilterChange: [{ type: i0.Output, args: ["quickFilterChange"] }], validationFailed: [{ type: i0.Output, args: ["validationFailed"] }], cellInfo: [{ type: i0.Output, args: ["cellInfo"] }], menuBarAction: [{ type: i0.Output, args: ["menuBarAction"] }], detailAction: [{ type: i0.Output, args: ["detailAction"] }], viewport: [{ type: i0.ViewChild, args: ['scrollViewport', { isSignal: true }] }], pinnedViewport: [{ type: i0.ViewChild, args: ['pinnedViewport', { isSignal: true }] }], rightPinnedViewport: [{ type: i0.ViewChild, args: ['rightPinnedViewport', { isSignal: true }] }], wrapperEl: [{ type: i0.ViewChild, args: ['wrapper', { isSignal: true }] }], horizontalScrollerEl: [{ type: i0.ViewChild, args: ['horizontalScroller', { isSignal: true }] }] } });
|
|
10451
|
+
}, template: "<div #wrapper class=\"ag-wrapper\" tabindex=\"0\" role=\"grid\" [attr.aria-label]=\"localeText().grid\"\n [attr.aria-rowcount]=\"ariaRowCount()\" [attr.aria-colcount]=\"ariaColCount()\"\n [attr.aria-multiselectable]=\"rowSelection() === 'multi' ? 'true' : null\"\n [attr.aria-readonly]=\"readonlyGrid() ? 'true' : null\" [attr.aria-busy]=\"loading() ? 'true' : null\"\n (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\" (focusin)=\"onGridFocusIn($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu(); closeMenuBarMenu()\">\n @if (visibleMenuBarItems().length > 0 || enableQuickFilter() || showFormulaBar()) {\n <div class=\"ag-toolbar\">\n @if (visibleMenuBarItems().length > 0) {\n <agrid-menu-bar [items]=\"visibleMenuBarItems()\" [context]=\"menuBarContext()\" [label]=\"localeText().actions\"\n [openItemId]=\"openMenuBarItemId()\" (openItemIdChange)=\"onMenuBarOpenItemChange($event)\"\n (action)=\"onMenuBarAction($event)\" />\n }\n @if (enableQuickFilter()) {\n <input class=\"ag-quick-filter\" type=\"search\" [value]=\"quickFilterValue()\" (input)=\"onQuickFilterInput($event)\"\n [placeholder]=\"localeText().quickFilterPlaceholder\" [attr.aria-label]=\"localeText().quickFilterPlaceholder\" />\n }\n @if (showFormulaBar()) {\n <div class=\"ag-formula-bar\" (click)=\"$event.stopPropagation()\">\n <span class=\"ag-formula-bar-label\">{{ formulaBarLabel() || 'fx' }}</span>\n <input\n class=\"ag-formula-bar-input\"\n type=\"text\"\n [value]=\"formulaBarDraft()\"\n [disabled]=\"!selectedCell() || readonlyGrid()\"\n (focus)=\"onFormulaBarFocus()\"\n (input)=\"onFormulaBarInput($event)\"\n (change)=\"commitFormulaBar()\"\n (blur)=\"onFormulaBarBlur()\"\n (keydown)=\"onFormulaBarKeydown($event)\"\n aria-label=\"Formula bar\"\n />\n </div>\n }\n </div>\n }\n <div class=\"ag-main-area\">\n <div class=\"ag-grid-split\" [class.ag-has-right-pane]=\"hasRightPinnedPane()\">\n @if (hasPinnedPane()) {\n <div class=\"ag-pinned-pane\" [style.width.px]=\"pinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"left\"\n [headerGroups]=\"pinnedHeaderGroups()\"\n [columns]=\"pinnedHeaderColumns()\"\n [gridTemplateColumns]=\"pinnedGridTemplateColumns()\"\n [paneWidth]=\"pinnedPaneWidth()\"\n [totalWidth]=\"pinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #leftRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\" [attr.data-control]=\"true\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isPinnedPaneRowSelected(item)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? pinnedGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell\" role=\"rowheader\" aria-colindex=\"1\"\n [class.ag-control-cell--reorder]=\"allowRowReorder()\"\n [class.ag-control-cell--marking]=\"enableRowMarking()\"\n [class.ag-control-cell--numbered]=\"showRowNumbers()\"\n (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\"\n (click)=\"onControlCellClick($event, item.originalIndex)\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\">\n @if (showRowNumbers()) {\n <span class=\"ag-row-number\">{{ rowNumbers().get(item.originalIndex) }}</span>\n }\n @if (canToggleDetail(item)) {\n <button class=\"ag-detail-toggle\" type=\"button\"\n [class.ag-detail-toggle--expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-expanded]=\"isDetailExpanded(item.originalIndex)\"\n [attr.aria-label]=\"localeText().toggleDetail\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"onDetailToggle(item.originalIndex); $event.stopPropagation()\">\u25B6</button>\n }\n @if (enableRowMarking()) {\n <input class=\"ag-row-marker\" type=\"checkbox\" [checked]=\"isRowMarked(item.originalIndex)\"\n [attr.aria-label]=\"localeText().markRow\" (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\" (change)=\"toggleRowMarked(item.originalIndex)\" />\n }\n </div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"pinnedColDefs()\" [paneHasSpans]=\"pinnedPaneHasSpans()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @if (showControlColumn()) {\n <div class=\"ag-control-cell ag-control-cell--reorder ag-ghost-handle\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-last]=\"bc.lastPinned\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body\" [style.width.px]=\"pinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"leftRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\">\n @if (showControlColumn()) {\n <div class=\"ag-footer-cell ag-footer-cell--control\" role=\"gridcell\" aria-colindex=\"1\"></div>\n }\n @for (bc of pinnedBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-last]=\"bc.lastPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"ag-scroll-pane\">\n <div #horizontalScroller class=\"ag-horizontal-scroll\" (scroll)=\"onHorizontalScroll()\">\n <agrid-pane-header\n variant=\"center\"\n [headerGroups]=\"scrollableHeaderGroups()\"\n [columns]=\"scrollableHeaderColumns()\"\n [gridTemplateColumns]=\"scrollableGridTemplateColumns()\"\n [paneWidth]=\"scrollableTotalWidth()\"\n [totalWidth]=\"scrollableTotalWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #bodyRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-add-row--selected]=\"item === null && isAddRowSelected()\" [class.ag-ghost-row]=\"item === 'ghost'\"\n [class.ag-group-header-row]=\"isGroupHeaderItem(item)\" [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? scrollableGridTemplateColumns() : null\"\n (pointerdown)=\"isDataRowItem(item) && onRowPointerDown($event, item.originalIndex)\"\n (click)=\"isDataRowItem(item) && onRowClick($event, item)\">\n @if (isDataRowItem(item)) {\n @if (columnWindow().leftWidth > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'1 / span ' + columnWindow().start\"></div>\n }\n @for (bc of virtualScrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"scrollableColDefs()\" [paneHasSpans]=\"scrollablePaneHasSpans()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\"\n (startEdit)=\"onStartEdit(item.originalIndex, ci)\" (draftChange)=\"onDraftChange($event)\"\n (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\" (treeToggle)=\"onTreeToggle(item)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n @if (columnWindowRightSpan() > 0) {\n <div class=\"ag-virtual-col-spacer\" aria-hidden=\"true\"\n [style.grid-column]=\"'span ' + columnWindowRightSpan()\"></div>\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-add-row-label\" (click)=\"onActivateAddRow()\">\n <span class=\"ag-add-row-icon\">+</span> {{ localeText().addRow }}\n </div>\n } @else if (item === 'ghost') {\n @for (bc of scrollableBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell\" [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\">{{\n getGhostCellDisplay(bc.col) }}</div>\n }\n } @else if (isDetailRowItem(item)) {\n <div class=\"ag-detail-panel\" [style.height.px]=\"detailRowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n <div [innerHTML]=\"detailHtml(item)\"></div>\n @if (detailColumn(); as detailCol) {\n <div class=\"ag-detail-column-field\">\n <span class=\"ag-detail-column-label\">{{ detailCol.header }}</span>\n @if (detailActions().length && isDetailFieldEditable(item)) {\n <div class=\"ag-detail-action-bar\" role=\"toolbar\" [attr.aria-label]=\"detailCol.header + localeText().templates\">\n @for (action of detailActions(); track action.id) {\n <button type=\"button\" class=\"ag-detail-action-btn\"\n (click)=\"applyDetailAction(item, action, $event)\">{{ action.label }}</button>\n }\n </div>\n }\n @if (detailEditingRow() === item.detailFor) {\n <textarea class=\"ag-detail-column-textarea\" [attr.data-detail-row]=\"item.detailFor\"\n [class.ag-detail-column-textarea--invalid]=\"!!detailValidationError()\"\n [value]=\"detailDraft()\" (input)=\"onDetailDraftInput($event)\"\n (pointerdown)=\"$event.stopPropagation()\"\n (keydown)=\"onDetailEditorKeydown(item, $event)\"\n (blur)=\"commitDetailFieldEdit(item)\"></textarea>\n @if (detailValidationError(); as message) {\n <span class=\"ag-detail-column-error\" role=\"alert\">{{ message }}</span>\n }\n } @else {\n <div class=\"ag-detail-column-value\" [class.ag-detail-column-value--editable]=\"isDetailFieldEditable(item)\"\n [attr.tabindex]=\"isDetailFieldEditable(item) ? 0 : null\"\n (click)=\"startDetailFieldEdit(item, $event)\"\n (keydown.enter)=\"startDetailFieldEdit(item, $event)\">{{ detailFieldDisplay(item) }}</div>\n }\n </div>\n }\n </div>\n } @else if (isPathTreeNodeItem(item)) {\n <div class=\"ag-path-tree-content\" [style.min-width.px]=\"scrollableTotalWidth()\"\n [style.padding-left.px]=\"treeRowLevel(item) * 16 + 8\"\n (click)=\"onTreeNodeClick(item); $event.stopPropagation()\"\n (dblclick)=\"onTreeNodeDoubleClick(item); $event.stopPropagation()\">\n <button type=\"button\" class=\"ag-tree-twisty\" [class.ag-tree-twisty--expanded]=\"treeRowExpanded(item)\"\n [attr.aria-expanded]=\"treeRowExpanded(item)\"\n (click)=\"onTreeToggle(item); $event.stopPropagation()\">\u25B6</button>\n <span>{{ pathTreeLabel(item) }}</span>\n @if (item.aggregates; as aggregates) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (col.field !== treeConfig()!.treeField && aggregates[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggregates[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n } @else {\n <div class=\"ag-group-header-content\" [style.min-width.px]=\"scrollableTotalWidth()\">\n <div class=\"ag-group-header-main\"\n (click)=\"onGroupHeaderClick(item.groupLabel); $event.stopPropagation()\">\n <span class=\"ag-group-icon\" [class.ag-group-icon--expanded]=\"!item.collapsed\">\u25B6</span>\n <span class=\"ag-group-label\">{{ item.groupLabel }}</span>\n @if (groupActions().length > 0) {\n <button class=\"ag-group-actions-btn\" [title]=\"localeText().actions\"\n (click)=\"openGroupActionsMenu($event, item.groupLabel)\">\u22EE</button>\n }\n <span class=\"ag-group-count\">{{ item.count }}</span>\n @if (getGroupDescription(item.groupLabel); as desc) {\n <span class=\"ag-group-description\">{{ desc }}</span>\n }\n @if (item.aggregates; as aggs) {\n <span class=\"ag-group-aggregates\">\n @for (col of visibleColDefs(); track col.field) {\n @if (hasAggregate(col) && aggs[col.field] !== undefined) {\n <span class=\"ag-group-aggregate\">\n <span class=\"ag-group-aggregate-col\">{{ col.header }}</span>\n <span class=\"ag-group-aggregate-op\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, aggs[col.field]) }}\n </span>\n }\n }\n </span>\n }\n </div>\n </div>\n }\n @if (isDataRowItem(item) && isRowPendingDelete(item.originalIndex)) {\n <div class=\"ag-delete-confirmation\" role=\"alertdialog\" [attr.aria-label]=\"localeText().confirmDeleteRow\"\n [style.left.px]=\"deleteConfirmationLeft()\" [style.width.px]=\"deleteConfirmationWidth() || null\"\n (pointerdown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <span class=\"ag-delete-confirmation-text\">{{ localeText().confirmDeleteRow }}</span>\n <button class=\"ag-delete-confirmation-btn ag-delete-confirmation-btn--yes\" type=\"button\"\n (click)=\"confirmPendingRowDelete()\">{{ localeText().confirmYes }}</button>\n <button class=\"ag-delete-confirmation-btn\" type=\"button\" data-delete-confirm-no\n (click)=\"cancelRowDelete()\">{{ localeText().confirmNo }}</button>\n </div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [agridVariableRowSize]=\"itemSizes()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom\" [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"bodyRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (bc of scrollableBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (hasRightPinnedPane()) {\n <div class=\"ag-pinned-pane ag-pinned-pane--right\" [style.width.px]=\"rightPinnedPaneWidth()\">\n <agrid-pane-header\n variant=\"right\"\n [headerGroups]=\"rightHeaderGroups()\"\n [columns]=\"rightHeaderColumns()\"\n [gridTemplateColumns]=\"rightGridTemplateColumns()\"\n [paneWidth]=\"rightPinnedPaneWidth()\"\n [totalWidth]=\"rightPinnedPaneWidth()\"\n [hasHeaderGroups]=\"hasHeaderGroups()\"\n [hasFilterableColumns]=\"hasFilterableColumns()\"\n [headerRowCount]=\"headerRowCount()\"\n [showControlColumn]=\"showControlColumn()\"\n [localeText]=\"localeText()\"\n [pivotHeaderLabel]=\"pivotHeaderLabel()\"\n [pivotRowColumnField]=\"pivotRowColumnField()\"\n [hasMultiSort]=\"hasMultiSort()\"\n [filterMenuField]=\"filterMenu()?.field ?? null\"\n [markedColumnFields]=\"markedColumnFields()\"\n (headerGroupPointerDown)=\"onHeaderGroupPointerDown($event.event, $event.fields, $event.label)\"\n (colHeaderPointerDown)=\"onColHeaderPointerDown($event.event, $event.field)\"\n (colHeaderClick)=\"onColHeaderClick($event.event, $event.field)\"\n (filterMenuOpen)=\"openFilterMenu($event.event, $event.field)\"\n (filterConditionMenuOpen)=\"openFilterMenu($event.event, $event.field, 'condition')\"\n (textFilterChange)=\"onTextFilterChange($event.event, $event.field)\"\n (resizeKeyDown)=\"onResizeKeyDown($event.event, $event.col)\"\n (resizeStart)=\"onResizeStart($event.event, $event.col)\"\n (autosizeColumn)=\"onAutosizeColumn($event.event, $event.col)\"\n />\n\n <ng-template #rightRow let-item let-ariaIndex=\"ariaIndex\">\n <div role=\"row\" [attr.aria-rowindex]=\"ariaIndex\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item) && !isDetailRowItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(item)\"\n [class.ag-detail-row]=\"isDetailRowItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [class.ag-row--marked]=\"isDataRowItem(item) && isRowMarked(item.originalIndex)\"\n [class.ag-row--pending-delete]=\"isDataRowItem(item) && isRowPendingDelete(item.originalIndex)\"\n [class.ag-row--indicating]=\"isDataRowItem(item) && rowIndicationActive(item.originalIndex)\"\n [class]=\"isDataRowItem(item) ? getRowClass(item.row, item.originalIndex) : ''\"\n [style.height.px]=\"rowPx(item)\"\n [style.--agrid-row-indication-color]=\"isDataRowItem(item) ? rowIndicationColor(item.originalIndex) : null\"\n [style.--agrid-row-indication-duration.ms]=\"isDataRowItem(item) ? rowIndicationDuration(item.originalIndex) : null\"\n [style.grid-template-columns]=\"isDataRowItem(item) || isLoadingRow(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n @let ci = bc.visibleColIndex;\n <agrid-cell [col]=\"col\" [paneColumns]=\"rightPinnedColDefs()\" [paneHasSpans]=\"rightPaneHasSpans()\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\" [localeText]=\"localeText()\"\n [displayValueOverride]=\"treeCellDisplayOverride(item, col)\" [row]=\"item.row\" [locale]=\"locale()\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\" [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [editable]=\"isColEditable(col, item.originalIndex) && !isTreeAggregateCell(item, col)\"\n [error]=\"cellValidationError(item.originalIndex, ci)\" [showInfoIcon]=\"showCellInfoIcon(col, item.row)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\" [selectTextOnEdit]=\"selectTextOnEdit()\"\n [treeCell]=\"isTreeCell(col)\" [treeLevel]=\"treeRowLevel(item)\" [treeExpandable]=\"treeRowExpandable(item)\"\n [treeExpanded]=\"treeRowExpanded(item)\" [class]=\"getCellClass(col, item.row[col.field], item.row)\"\n [class.ag-cell--range-selected]=\"isRangeSelected(item.originalIndex, ci)\"\n [class.ag-cell--fill-preview]=\"isFillPreviewCell(item.originalIndex, ci)\"\n [class.ag-cell--fill-handle]=\"isFillHandleCell(item.originalIndex, ci)\"\n [class.ag-cell--changed]=\"isCellChanged(item.originalIndex, col.field)\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--find-match]=\"isFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--find-active]=\"isActiveFindMatchCell(item.originalIndex, ci)\"\n [class.ag-cell--pinned]=\"true\" [class.ag-cell--pinned-first]=\"bc.firstRightPinned\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\" (editorCommit)=\"onEditorCommit()\" (editorCancel)=\"onEditorCancel()\"\n (booleanToggle)=\"onBooleanToggle(item.originalIndex, ci, $event)\"\n (infoClick)=\"onCellInfo(item.originalIndex, col, item.row)\" (treeToggle)=\"onTreeToggle(item)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (isLoadingRow(item)) {\n <div class=\"ag-loading-row\" aria-hidden=\"true\"><span></span></div>\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (bc of rightBodyColumns(); track bc.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [class.ag-cell--pinned-first]=\"bc.firstRightPinned\">{{ getGhostCellDisplay(bc.col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-row-spacer\"></div>\n }\n </div>\n </ng-template>\n\n @if (hasPinnedTopRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--top ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedTopItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + $index }\" />\n }\n </div>\n }\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [agridVariableRowSize]=\"itemSizes()\" [style.width.px]=\"rightPinnedPaneWidth()\"\n (scroll)=\"onRightPinnedBodyScroll()\">\n <ng-container *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\">\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: di + headerRowCount() + 1 + pinnedTopItems().length }\" />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n\n @if (hasPinnedBottomRows()) {\n <div class=\"ag-pinned-rows ag-pinned-rows--bottom ag-pinned-body ag-right-pinned-body\"\n [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (item of pinnedBottomItems(); track item.originalIndex) {\n <ng-container [ngTemplateOutlet]=\"rightRow\"\n [ngTemplateOutletContext]=\"{ $implicit: item, ariaIndex: headerRowCount() + 1 + pinnedTopItems().length + displayItems().length + $index }\" />\n }\n </div>\n }\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (bc of rightBodyColumns(); track bc.field) {\n @let col = bc.col;\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column--marked]=\"markedColumnFields().has(col.field)\"\n [class.ag-column-reorder-item--dragging]=\"bc.dragging\"\n [style.transform]=\"'translateX(' + bc.reorderOffset + 'px)'\"\n [attr.aria-colindex]=\"bc.ariaColIndex\"\n [class.ag-footer-cell--pinned-first]=\"bc.firstRightPinned\">\n @if (hasAggregate(col)) {\n <span class=\"ag-footer-label\">{{ getAggregateLabel(col) }}</span>\n {{ getFooterDisplay(col, footerValues()[col.field]) }}\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (loading()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ localeText().loading }}</div>\n } @else if (isEmpty()) {\n <div class=\"ag-state-overlay\" role=\"status\" aria-live=\"polite\">{{ emptyTextLabel() }}</div>\n }\n\n @if (showSidebar()) {\n <agrid-sidebar [open]=\"sidebarOpen()\" [activeTab]=\"sidebarTab()\" [columns]=\"colDefs()\"\n [pivotColumns]=\"sidebarPivotColumns()\" [pivotConfig]=\"provider().pivotConfig\" [headerGroups]=\"headerGroups()\"\n [row]=\"sidebarRow()\" [rowIndex]=\"selectedRowIndex()\" [hiddenColumns]=\"sidebarHiddenColumns()\" [locale]=\"locale()\"\n [localeText]=\"localeText()\" [readonlyGrid]=\"readonlyGrid()\" [useSidebarEditor]=\"useSidebarEditor()\"\n [isCellEditable]=\"isCellEditableForRow\" [errors]=\"sidebarValidationErrors()\" (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\" (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (toggleColumnGroup)=\"onSidebarToggleColumnGroup($event.fields, $event.visible)\"\n (pivotChange)=\"onSidebarPivotChange($event)\" (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\" />\n }\n </div><!-- /.ag-main-area -->\n\n @if (!hideGridStatusBar() && selectionSummaryDisplay(); as summary) {\n <div class=\"ag-status-bar\" role=\"status\" aria-live=\"polite\">\n <span><strong>{{ localeText().aggregateCount }}:</strong> {{ summary.count }}</span>\n <span><strong>{{ localeText().aggregateSum }}:</strong> {{ summary.sum }}</span>\n <span><strong>{{ localeText().aggregateAvg }}:</strong> {{ summary.average }}</span>\n <span><strong>{{ localeText().aggregateMin }}:</strong> {{ summary.min }}</span>\n <span><strong>{{ localeText().aggregateMax }}:</strong> {{ summary.max }}</span>\n </div>\n }\n\n @if (showPagination()) {\n <nav class=\"ag-pagination\" [attr.aria-label]=\"localeText().pagination\">\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().firstPage\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\" [disabled]=\"control()!.currentPage() <= 1\"\n (click)=\"goToPrevPage()\">\u2039</button>\n <span class=\"ag-page-info\" aria-live=\"polite\">{{ control()!.currentPage() }} / {{ totalPages() }}</span>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().next\" (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\" (click)=\"goToLastPage()\">\u00BB</button>\n <span class=\"ag-page-count\">{{ localeText().rows(filteredRowCount()) }}</span>\n </nav>\n }\n\n @if (findOpen()) {\n <agrid-find-panel [query]=\"findQuery()\" [matchCount]=\"findMatches().length\" [activeIndex]=\"findActiveIndex()\"\n [localeText]=\"localeText()\" (queryChange)=\"onFindInput($event)\" (previous)=\"goToFindMatch(-1)\"\n (next)=\"goToFindMatch(1)\" (close)=\"closeFind()\" />\n }\n\n <!-- Row context menu -->\n @if (contextMenu(); as menu) {\n @if(hasContextMenuEntries()) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @if (!treeConfig()) {\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n }\n @if (!readonlyGrid()) {\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n }\n </div>\n }\n }\n\n <!-- Cell context menu -->\n @if (cellContextMenuState(); as menu) {\n @let col = getColDef(menu.field)!;\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyCellToClipboard(menu.rowIndex, col)\">{{\n localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.rowIndex)\">{{ localeText().copyRow\n }}</button>\n @if (!treeConfig()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @if (rowPinState(menu.rowIndex)) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, null)\">{{ localeText().unpinRow\n }}</button>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'top')\">{{ localeText().pinRowTop\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onPinRow(menu.rowIndex, 'bottom')\">{{\n localeText().pinRowBottom }}</button>\n }\n }\n @if (allowAddRows() && !readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex)\">{{ localeText().insertRowAbove\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{\n localeText().insertRowBelow }}</button>\n }\n @if (!readonlyGrid()) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n <button class=\"ag-context-item ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">{{\n localeText().deleteRow }}</button>\n }\n @if (cellMenuItems().length) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n @for (item of cellMenuItems(); track $index) {\n @if (item === null) {\n <div class=\"ag-context-separator\" role=\"separator\"></div>\n } @else {\n <button class=\"ag-context-item\" role=\"menuitem\" [class.ag-context-item--danger]=\"item.danger\"\n [disabled]=\"item.disabled\" (click)=\"runCellMenuItem(item, menu)\">{{\n item.label }}</button>\n }\n }\n }\n </div>\n }\n\n <!-- Group actions menu -->\n @if (groupActionsMenu(); as menu) {\n <div class=\"ag-context-menu\" role=\"menu\" [style.left.px]=\"menu.x\" [style.top.px]=\"menu.y\"\n (click)=\"$event.stopPropagation()\">\n @for (action of groupActions(); track action.label) {\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"onGroupAction(action, menu.label)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <!-- Filter dropdown -->\n @if (filterMenu(); as menu) {\n <agrid-column-menu [x]=\"menu.x\" [y]=\"menu.y\" [header]=\"getColDef(menu.field)?.header ?? menu.field\"\n [sortDir]=\"getSort(menu.field)\" [sortable]=\"menu.mode === 'column' && sortOption() !== 'none'\"\n [showColumnActions]=\"menu.mode === 'column' && !!control()\"\n [showAggregationActions]=\"menu.mode === 'column' && pivotRowColumnField()===null\"\n [pinned]=\"getColumnPinState(menu.field)\" [groupable]=\"menu.mode === 'column' && !!getColDef(menu.field)?.groupable\"\n [grouped]=\"isGroupedByField(menu.field)\" [filterable]=\"!!getColDef(menu.field)?.filterable\"\n [column]=\"getColDef(menu.field) ?? null\" [control]=\"control()\" [filter]=\"getColumnFilter(menu.field)\"\n [showFilterActions]=\"menu.mode === 'column'\"\n [showValueFilter]=\"menu.mode === 'column' && (!serverSideFiltering() || !!getColDef(menu.field)?.values?.length)\"\n [filterType]=\"getMenuFilterType(menu.field)\" [operator]=\"getMenuOperator(menu.field)\"\n [operand]=\"getMenuOperand(menu.field)\" [operand2]=\"getMenuOperand2(menu.field)\"\n (operatorChange)=\"onMenuOperatorChange(menu.field, $event)\"\n (operandChange)=\"onMenuOperandChange(menu.field, $event)\"\n (operand2Change)=\"onMenuOperand2Change(menu.field, $event)\" [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\" [valueItems]=\"(serverSideFiltering() && !getColDef(menu.field)?.values?.length)\n || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\" [localeText]=\"localeText()\"\n [sortPriority]=\"getSortPriority(menu.field)\" [hasMultiSort]=\"hasMultiSort()\" (sort)=\"onMenuSort(menu.field, $event)\"\n (resetSort)=\"onMenuResetSort(menu.field, $event)\" (autosize)=\"onMenuAutosizeColumn(menu.field)\"\n (togglePin)=\"onMenuTogglePin(menu.field)\" (togglePinRight)=\"onMenuTogglePinRight(menu.field)\"\n (hide)=\"onMenuHideColumn(menu.field)\" (toggleGroup)=\"onMenuToggleGroupBy(menu.field)\"\n (clearFilter)=\"onMenuClearFilter(menu.field)\" (clearAll)=\"onMenuClearAll()\"\n (searchChange)=\"onFilterMenuSearch($event)\" (toggleAll)=\"onMenuToggleAll(menu.field)\"\n (toggleValue)=\"onMenuToggleValue(menu.field, $event)\" [aggregate]=\"getEffectiveAggregate(getColDef(menu.field)!)\"\n (filterReplace)=\"onMenuReplaceFilter(menu.field, $event)\" (close)=\"closeOpenMenus()\"\n [customItems]=\"menu.mode === 'column' ? getColDef(menu.field)?.headerMenuItems ?? [] : []\"\n (customAction)=\"onColumnHeaderAction(menu.field, $event)\"\n (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\n }\n\n @if (columnDragPreview(); as preview) {\n <div class=\"ag-column-drag-preview\" [style.left.px]=\"preview.x\" [style.top.px]=\"preview.y\"\n [style.width.px]=\"preview.width\" [style.height.px]=\"preview.height\">\n <span>{{ preview.label }}</span>\n </div>\n }\n</div>\n", styles: ["@layer agrid-defaults{:host{--agrid-color-text: #24292f;--agrid-color-text-muted: #57606a;--agrid-color-accent: #1a73e8;--agrid-color-accent-subtle: #e8f0fe;--agrid-color-accent-fg: #1558b0;--agrid-color-accent-border: #c8d8f8;--agrid-color-danger: #d1242f;--agrid-color-danger-subtle: #fff1f0;--agrid-color-border: #d0d7de;--agrid-color-bg: #ffffff;--agrid-color-bg-subtle: #fafbfc;--agrid-color-bg-muted: #f6f8fa;--agrid-color-shadow: rgba(140, 149, 159, .2);--agrid-color-bg-stripe: #f0f2f5;--agrid-color-cell-changed: #f59e0b;--agrid-color-row-marked: #fff8c5;--agrid-color-column-marked: #e8f0fe;--agrid-color-menu-bg: #ffffff}}:host{display:flex;flex-direction:column;min-width:0;max-width:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--agrid-color-text)}.ag-wrapper{position:relative;display:flex;flex-direction:column;flex:1;min-width:0;min-height:0;border:1px solid var(--agrid-color-border);overflow:hidden;outline:none;border-radius:4px}.ag-state-overlay{position:absolute;inset:34px 0 0;display:flex;align-items:center;justify-content:center;color:var(--agrid-color-text-muted);background:color-mix(in srgb,var(--agrid-color-bg) 78%,transparent);pointer-events:none;z-index:3}.ag-status-bar{display:flex;flex-shrink:0;align-items:center;justify-content:flex-end;gap:16px;min-height:28px;padding:3px 10px;box-sizing:border-box;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);color:var(--agrid-color-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.ag-status-bar strong{color:var(--agrid-color-text);font-weight:600}@media(max-width:640px){.ag-status-bar{justify-content:flex-start;gap:10px;overflow-x:auto}.ag-status-bar span{white-space:nowrap}}.ag-row>agrid-cell,.ag-ghost-cell,.ag-footer-cell{transition:transform .16s cubic-bezier(.2,0,0,1),opacity .1s ease;will-change:transform}.ag-virtual-col-spacer{pointer-events:none}.ag-loading-row{grid-column:1 / -1;display:flex;align-items:center;padding:0 10px;box-sizing:border-box;border-bottom:1px solid var(--agrid-color-border)}.ag-loading-row span{width:min(220px,55%);height:8px;border-radius:999px;background:color-mix(in srgb,var(--agrid-color-text-muted) 18%,transparent)}.ag-column-reorder-item--dragging{opacity:.12}.ag-column-drag-preview{position:fixed;z-index:1000;display:flex;align-items:flex-start;padding:8px 10px;border:1px solid var(--agrid-color-accent);border-radius:5px;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-bg) 94%,var(--agrid-color-accent));box-shadow:0 10px 28px var(--agrid-color-shadow);font-weight:600;line-height:16px;box-sizing:border-box;pointer-events:none;opacity:.96}.ag-main-area{display:flex;flex:1;min-height:0;overflow:hidden}.ag-grid-split{display:flex;flex:1;min-width:0;min-height:0;overflow:hidden}.ag-pinned-pane{flex-shrink:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-scroll-pane{flex:1;min-width:0;min-height:0;display:flex}.ag-horizontal-scroll{flex:1;min-width:0;min-height:0;overflow-x:auto;overflow-y:hidden;display:flex;flex-direction:column}.ag-body{flex:1;overflow-x:clip;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-horizontal-scroll{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.18) transparent}.ag-body::-webkit-scrollbar,.ag-horizontal-scroll::-webkit-scrollbar{width:8px;height:8px}.ag-body::-webkit-scrollbar-track,.ag-horizontal-scroll::-webkit-scrollbar-track{background:transparent}.ag-body::-webkit-scrollbar-thumb,.ag-horizontal-scroll::-webkit-scrollbar-thumb{background:#0000002e;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-body::-webkit-scrollbar-thumb:hover,.ag-horizontal-scroll::-webkit-scrollbar-thumb:hover{background:#00000052;border-radius:10px;border:2px solid transparent;background-clip:padding-box}.ag-pinned-body{overflow:hidden}.ag-right-pinned-body{overflow-y:auto}.ag-has-right-pane .ag-body:not(.ag-pinned-body){scrollbar-width:none}.ag-has-right-pane .ag-body:not(.ag-pinned-body)::-webkit-scrollbar{display:none}.ag-row{display:grid;position:relative;--agrid-row-indication-duration: 1s}.ag-row--pending-delete>:not(.ag-delete-confirmation){opacity:.2;pointer-events:none;transition:opacity .14s ease}.ag-delete-confirmation{position:absolute;top:0;bottom:0;z-index:7;display:flex;align-items:center;justify-content:center;gap:8px;min-width:min(100%,320px);padding:2px 12px;box-sizing:border-box;color:var(--agrid-color-text);background:color-mix(in srgb,var(--agrid-color-danger-subtle) 88%,transparent);border-block:1px solid color-mix(in srgb,var(--agrid-color-danger) 35%,transparent)}.ag-delete-confirmation-text{font-weight:600;white-space:nowrap}.ag-delete-confirmation-btn{min-width:42px;padding:3px 9px;border:1px solid var(--agrid-color-border);border-radius:4px;color:var(--agrid-color-text);background:var(--agrid-color-bg);font:inherit;cursor:pointer}.ag-delete-confirmation-btn:hover,.ag-delete-confirmation-btn:focus-visible{border-color:var(--agrid-color-accent);outline:none}.ag-delete-confirmation-btn--yes{color:#fff;border-color:var(--agrid-color-danger);background:var(--agrid-color-danger)}.ag-delete-confirmation-btn--yes:hover,.ag-delete-confirmation-btn--yes:focus-visible{border-color:color-mix(in srgb,var(--agrid-color-danger) 75%,#000);background:color-mix(in srgb,var(--agrid-color-danger) 85%,#000)}:host(.ag-zebra) .ag-row--odd agrid-cell:not(.editing){background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd .ag-control-cell{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd:hover .ag-control-cell{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned,:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}:host(.ag-zebra) .ag-row--odd .ag-cell--pinned-first{background:var(--agrid-color-bg-stripe)}:host(.ag-zebra) .ag-row--odd:hover .ag-cell--pinned-first{background:var(--agrid-color-bg-muted)}:host(.ag-zebra) .ag-row--odd.ag-row--selected .ag-cell--pinned-first{background:var(--agrid-color-accent-subtle)}.ag-row:hover agrid-cell:not(.editing){background:var(--agrid-color-bg-muted)}.ag-row--selected agrid-cell:not(.editing){background:var(--agrid-color-accent-subtle)}.ag-row--marked agrid-cell:not(.editing),.ag-row--marked .ag-control-cell{background:var(--agrid-color-row-marked)}.ag-row--marked{box-shadow:inset 3px 0 #bf8700}.ag-row--indicating:after{content:\"\";position:absolute;inset:0;z-index:6;pointer-events:none;background:var(--agrid-row-indication-color);animation:ag-row-indication-fade var(--agrid-row-indication-duration) ease-out forwards}@keyframes ag-row-indication-fade{0%{opacity:.35}to{opacity:0}}.ag-row agrid-cell.ag-column--marked:not(.editing),.ag-footer-cell.ag-column--marked{background:var(--agrid-color-column-marked)}.ag-row--selected.ag-row--marked{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--range-selected:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent-border)}.ag-row agrid-cell.ag-cell--find-match:not(.editing){background:#fff7cc}.ag-row agrid-cell.ag-cell--find-active:not(.editing){background:#ffe58a;box-shadow:inset 0 0 0 2px #b7791f}.ag-row agrid-cell.ag-cell--range-selected.selected:not(.editing){box-shadow:inset 0 0 0 2px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-preview:not(.editing){background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1px var(--agrid-color-accent)}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing){position:relative}.ag-row agrid-cell.ag-cell--fill-handle:not(.editing):after{content:\"\";position:absolute;right:1px;bottom:1px;width:6px;height:6px;background:var(--agrid-color-accent);border:1px solid var(--agrid-color-bg);box-sizing:border-box;cursor:crosshair;z-index:4}.ag-row--selected .ag-control-cell{background:var(--agrid-color-accent-subtle)}.ag-row--selected{box-shadow:inset 3px 0 0 var(--agrid-color-accent)}.ag-control-cell{z-index:2;border-right:1px solid var(--agrid-color-border);border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle);cursor:context-menu;display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;flex-direction:row-reverse}.ag-control-cell:after{content:\"\\22ee\";font-size:11px;color:var(--agrid-color-border);line-height:1}.ag-control-cell:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder{cursor:grab}.ag-control-cell--marking:not(.ag-control-cell--reorder){cursor:pointer}.ag-control-cell--reorder:after{content:\"\\283f\";font-size:13px;color:var(--agrid-color-text)}.ag-control-cell--reorder:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--numbered:after{content:none}.ag-control-cell--reorder:active{cursor:grabbing}.ag-row-number{min-width:0;color:var(--agrid-color-text-muted);font-size:11px;font-variant-numeric:tabular-nums;line-height:1;overflow:hidden;text-align:center;text-overflow:ellipsis;-webkit-user-select:none;user-select:none;white-space:nowrap}.ag-row-marker{position:relative;z-index:1;width:14px;height:14px;margin:0;accent-color:var(--agrid-color-accent);cursor:pointer}.ag-ghost-row{background:var(--agrid-color-accent-subtle);box-shadow:inset 0 0 0 1.5px var(--agrid-color-accent);pointer-events:none;animation:ag-ghost-in .1s ease}@keyframes ag-ghost-in{0%{opacity:0}to{opacity:1}}.ag-ghost-handle:after{color:var(--agrid-color-accent)!important}.ag-ghost-cell{display:flex;align-items:center;padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;border-right:1px solid var(--agrid-color-accent-border);color:var(--agrid-color-accent-fg);font-size:13px;box-sizing:border-box;-webkit-user-select:none;user-select:none}.ag-ghost-cell:last-child{border-right:none}.ag-pinned-row-spacer,.ag-pinned-group-spacer{height:100%;border-bottom:1px solid var(--agrid-color-border);box-sizing:border-box}.ag-pinned-group-spacer{background:var(--agrid-color-bg-muted)}.ag-context-menu{position:fixed;z-index:1000;background:var(--agrid-color-bg-subtle);border:1px solid var(--agrid-color-border);border-radius:6px;box-shadow:0 8px 24px var(--agrid-color-shadow);min-width:160px;padding:4px 0;font-size:13px}.ag-context-item{display:block;width:100%;padding:6px 16px;text-align:left;background:none;border:none;cursor:pointer;color:var(--agrid-color-text);font:inherit}.ag-context-item:hover{background:var(--agrid-color-bg-muted)}.ag-context-separator{height:1px;background:var(--agrid-color-border);margin:3px 0}.ag-context-item--danger{color:var(--agrid-color-danger)}.ag-context-item--danger:hover{background:var(--agrid-color-danger-subtle)}.ag-group-header-row{display:flex;align-items:stretch;background:var(--agrid-color-bg-muted);border-bottom:1px solid var(--agrid-color-border);overflow:hidden}.ag-path-tree-content{display:flex;align-items:center;gap:4px;height:100%;box-sizing:border-box;color:var(--agrid-color-text);font-weight:600;border-bottom:1px solid var(--agrid-color-border)}.ag-path-tree-content .ag-tree-twisty{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;color:inherit;background:transparent;cursor:pointer;font-size:10px;transition:transform .12s ease}.ag-path-tree-content .ag-tree-twisty--expanded{transform:rotate(90deg)}.ag-group-header-content{display:flex;align-items:stretch;height:100%;width:100%;-webkit-user-select:none;user-select:none}.ag-group-header-main{display:flex;align-items:center;gap:6px;padding:0 10px;flex:1;min-width:0;cursor:pointer}.ag-group-header-main:hover{background:var(--agrid-color-bg-subtle)}.ag-group-description{font-size:11px;color:var(--agrid-color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-group-actions-btn{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border:none;background:none;border-radius:3px;cursor:pointer;color:var(--agrid-color-text-muted);font-size:14px;padding:0}.ag-group-actions-btn:hover{background:var(--agrid-color-bg-muted);color:var(--agrid-color-text)}.ag-group-icon{font-size:9px;color:var(--agrid-color-text-muted);line-height:1;display:inline-block;transition:transform .15s ease}.ag-group-icon--expanded{transform:rotate(90deg)}.ag-group-label{font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-group-count{font-size:11px;color:var(--agrid-color-text-muted);background:var(--agrid-color-bg);border:1px solid var(--agrid-color-border);border-radius:10px;padding:0 7px;line-height:16px}.ag-group-aggregates{display:inline-flex;align-items:center;gap:10px;margin-left:4px;flex-wrap:wrap}.ag-group-aggregate{font-size:11px;color:var(--agrid-color-text);white-space:nowrap}.ag-group-aggregate-col{color:var(--agrid-color-text-muted);margin-right:4px}.ag-group-aggregate-op{color:var(--agrid-color-text-muted);margin-right:3px}.ag-footer{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-top:2px solid var(--agrid-color-border)}.ag-footer-cell{display:flex;align-items:center;gap:4px;padding:0 6px;height:30px;border-right:1px solid var(--agrid-color-border);box-sizing:border-box;overflow:hidden;white-space:nowrap;font-weight:600;font-size:12px;color:var(--agrid-color-text)}.ag-footer-cell:last-child{border-right:none}.ag-footer-cell--control{background:var(--agrid-color-bg-subtle);border-right:1px solid var(--agrid-color-border)}.ag-footer-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-footer-label{font-size:10px;font-weight:400;color:var(--agrid-color-text-muted);flex-shrink:0}.ag-pagination{display:flex;align-items:center;gap:4px;padding:0 10px;height:34px;flex-shrink:0;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted);font-size:12px;color:var(--agrid-color-text-muted)}.ag-page-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;border:1px solid var(--agrid-color-border);border-radius:3px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font-size:13px;cursor:pointer;padding:0;line-height:1}.ag-page-btn:hover:not(:disabled){background:var(--agrid-color-bg-muted);border-color:var(--agrid-color-text-muted)}.ag-page-btn:disabled{opacity:.35;cursor:default}.ag-page-info{padding:0 6px;font-weight:500;color:var(--agrid-color-text);min-width:48px;text-align:center}.ag-page-count{margin-left:auto;color:var(--agrid-color-text-muted)}.ag-add-row{border-bottom:1px dashed var(--agrid-color-border);color:var(--agrid-color-text-muted);cursor:pointer}.ag-add-row:hover .ag-add-row-label{background:var(--agrid-color-bg-muted)}.ag-add-row--selected .ag-add-row-label{outline:2px solid var(--agrid-color-accent);outline-offset:-2px}.ag-add-row-label{display:flex;align-items:center;gap:4px;height:100%;padding:0 6px;font-size:12px;-webkit-user-select:none;user-select:none}.ag-add-row-icon{font-size:16px;line-height:1;color:var(--agrid-color-text-muted)}.ag-pinned-pane--right{border-left:1px solid var(--agrid-color-border);border-right:none;box-shadow:-3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned{background:var(--agrid-color-bg)}.ag-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-cell--pinned-first{box-shadow:none}.ag-row:hover .ag-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-row--selected .ag-cell--pinned,.ag-row .ag-cell--pinned.ag-cell--range-selected,.ag-row .ag-cell--pinned.ag-cell--fill-preview{background:var(--agrid-color-accent-subtle)}.ag-row .ag-cell--pinned.ag-cell--find-match{background:#fff7cc}.ag-row .ag-cell--pinned.ag-cell--find-active{background:#ffe58a}.ag-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;padding:6px 8px;border-bottom:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-subtle)}.ag-quick-filter{margin-left:auto;width:100%;max-width:260px;height:30px;padding:0 10px;border:1px solid var(--agrid-color-border);border-radius:4px;background:var(--agrid-color-bg);color:var(--agrid-color-text)}.ag-quick-filter:focus{border-color:var(--agrid-color-accent-border)}.ag-formula-bar{display:flex;align-items:center;flex:1 1 360px;min-width:220px;height:30px;border:1px solid var(--agrid-color-border);border-radius:4px;overflow:hidden;background:var(--agrid-color-bg)}.ag-formula-bar-label{display:inline-flex;align-items:center;justify-content:center;flex:0 0 74px;height:100%;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted);color:var(--agrid-color-text-muted);font-size:12px;font-weight:650;font-variant-numeric:tabular-nums}.ag-formula-bar-input{flex:1 1 auto;min-width:0;height:100%;border:0;outline:0;padding:0 9px;box-sizing:border-box;background:transparent;color:var(--agrid-color-text);font:inherit;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace}.ag-formula-bar-input:disabled{color:var(--agrid-color-text-muted);cursor:not-allowed}.ag-formula-bar:focus-within{border-color:var(--agrid-color-accent-border)}.ag-detail-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;font-size:9px;line-height:1;color:var(--agrid-color-text-muted);transition:transform .12s ease,color .12s ease}.ag-detail-toggle:hover{color:var(--agrid-color-text)}.ag-detail-toggle--expanded{transform:rotate(90deg)}.ag-detail-row{display:block;position:relative;box-sizing:border-box}.ag-detail-panel{box-sizing:border-box;height:100%;overflow:auto;padding:8px 12px;background:var(--agrid-color-bg-subtle);border-bottom:1px solid var(--agrid-color-border)}.ag-detail-column-field{display:grid;gap:4px;margin-top:10px}.ag-detail-column-label{color:var(--agrid-color-text-muted);font-size:10px;font-weight:600;letter-spacing:.4px;text-transform:uppercase}.ag-detail-action-bar{display:flex;flex-wrap:wrap;gap:6px}.ag-detail-action-btn{border:1px solid var(--agrid-color-border);border-radius:3px;padding:4px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;font-size:12px;line-height:1.3;cursor:pointer}.ag-detail-action-btn:hover,.ag-detail-action-btn:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-value,.ag-detail-column-textarea{min-height:54px;box-sizing:border-box;border:1px solid var(--agrid-color-border);border-radius:3px;padding:7px 8px;background:var(--agrid-color-bg);color:var(--agrid-color-text);font:inherit;line-height:1.4;white-space:pre-wrap}.ag-detail-column-value--editable{cursor:text}.ag-detail-column-value--editable:hover,.ag-detail-column-value--editable:focus,.ag-detail-column-textarea:focus{border-color:var(--agrid-color-accent-border);outline:none}.ag-detail-column-textarea{width:100%;height:120px;resize:vertical;user-select:text;-webkit-user-select:text;cursor:text}.ag-detail-column-textarea--invalid{border-color:var(--agrid-color-danger)}.ag-detail-column-error{color:var(--agrid-color-danger);font-size:12px}.ag-pinned-rows{position:relative;z-index:3;flex:none;background:var(--agrid-color-bg)}.ag-pinned-rows--top{box-shadow:0 2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows--bottom{box-shadow:0 -2px 4px -2px var(--agrid-color-shadow)}.ag-pinned-rows .ag-row{background:var(--agrid-color-bg-subtle)}\n"] }]
|
|
10452
|
+
}], ctorParameters: () => [], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }], cellEdit: [{ type: i0.Output, args: ["cellEdit"] }], recordEdit: [{ type: i0.Output, args: ["recordEdit"] }], rowRemoved: [{ type: i0.Output, args: ["rowRemoved"] }], prepareAddRecord: [{ type: i0.Output, args: ["prepareAddRecord"] }], rowReorder: [{ type: i0.Output, args: ["rowReorder"] }], rowSelect: [{ type: i0.Output, args: ["rowSelect"] }], rowMark: [{ type: i0.Output, args: ["rowMark"] }], columnMark: [{ type: i0.Output, args: ["columnMark"] }], columnHeaderAction: [{ type: i0.Output, args: ["columnHeaderAction"] }], firstDataRendered: [{ type: i0.Output, args: ["firstDataRendered"] }], rowDoubleClicked: [{ type: i0.Output, args: ["rowDoubleClicked"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], treeNodeClick: [{ type: i0.Output, args: ["treeNodeClick"] }], settingsChange: [{ type: i0.Output, args: ["settingsChange"] }], treeNodeDoubleClicked: [{ type: i0.Output, args: ["treeNodeDoubleClicked"] }], rowChanged: [{ type: i0.Output, args: ["rowChanged"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], serverQueryChange: [{ type: i0.Output, args: ["serverQueryChange"] }], quickFilterChange: [{ type: i0.Output, args: ["quickFilterChange"] }], validationFailed: [{ type: i0.Output, args: ["validationFailed"] }], cellInfo: [{ type: i0.Output, args: ["cellInfo"] }], cellSelect: [{ type: i0.Output, args: ["cellSelect"] }], menuBarAction: [{ type: i0.Output, args: ["menuBarAction"] }], detailAction: [{ type: i0.Output, args: ["detailAction"] }], viewport: [{ type: i0.ViewChild, args: ['scrollViewport', { isSignal: true }] }], pinnedViewport: [{ type: i0.ViewChild, args: ['pinnedViewport', { isSignal: true }] }], rightPinnedViewport: [{ type: i0.ViewChild, args: ['rightPinnedViewport', { isSignal: true }] }], wrapperEl: [{ type: i0.ViewChild, args: ['wrapper', { isSignal: true }] }], horizontalScrollerEl: [{ type: i0.ViewChild, args: ['horizontalScroller', { isSignal: true }] }] } });
|
|
9597
10453
|
|
|
9598
10454
|
let nextPageSelectorId = 0;
|
|
9599
10455
|
/** Compact previous/input/dropdown/next control for navigating a labeled page list. */
|
|
@@ -10326,138 +11182,16 @@ class AgridChartComponent {
|
|
|
10326
11182
|
});
|
|
10327
11183
|
}
|
|
10328
11184
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10329
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridChartComponent, isStandalone: true, selector: "agrid-chart", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template:
|
|
10330
|
-
<svg
|
|
10331
|
-
class="agrid-chart__svg"
|
|
10332
|
-
role="img"
|
|
10333
|
-
[attr.width]="width()"
|
|
10334
|
-
[attr.height]="height()"
|
|
10335
|
-
>
|
|
10336
|
-
@for (g of layout().gridlines; track $index) {
|
|
10337
|
-
<line class="agrid-chart__grid" [attr.x1]="g.x1" [attr.y1]="g.y1" [attr.x2]="g.x2" [attr.y2]="g.y2" />
|
|
10338
|
-
}
|
|
10339
|
-
@for (a of layout().areas; track $index) {
|
|
10340
|
-
<path [attr.d]="a.d" [attr.fill]="a.color" fill-opacity="0.15" />
|
|
10341
|
-
}
|
|
10342
|
-
@for (l of layout().lines; track $index) {
|
|
10343
|
-
<path
|
|
10344
|
-
class="agrid-chart__line"
|
|
10345
|
-
fill="none"
|
|
10346
|
-
[attr.d]="l.d"
|
|
10347
|
-
[attr.stroke]="l.color"
|
|
10348
|
-
/>
|
|
10349
|
-
}
|
|
10350
|
-
@for (p of layout().points; track $index) {
|
|
10351
|
-
<circle [attr.cx]="p.x" [attr.cy]="p.y" r="2" [attr.fill]="p.color" />
|
|
10352
|
-
}
|
|
10353
|
-
@for (b of layout().bars; track $index) {
|
|
10354
|
-
<rect rx="1" [attr.x]="b.x" [attr.y]="b.y" [attr.width]="b.width" [attr.height]="b.height" [attr.fill]="b.color" />
|
|
10355
|
-
}
|
|
10356
|
-
@for (s of layout().slices; track $index) {
|
|
10357
|
-
<path class="agrid-chart__slice" [attr.d]="s.d" [attr.fill]="s.color" />
|
|
10358
|
-
}
|
|
10359
|
-
@for (lbl of layout().axisLabels; track $index) {
|
|
10360
|
-
<text
|
|
10361
|
-
class="agrid-chart__axis"
|
|
10362
|
-
[attr.x]="lbl.x"
|
|
10363
|
-
[attr.y]="lbl.y"
|
|
10364
|
-
[attr.text-anchor]="lbl.anchor"
|
|
10365
|
-
[attr.dominant-baseline]="lbl.baseline"
|
|
10366
|
-
>{{ lbl.text }}</text>
|
|
10367
|
-
}
|
|
10368
|
-
@if (sliceLabels()) {
|
|
10369
|
-
@for (s of layout().slices; track $index) {
|
|
10370
|
-
<text
|
|
10371
|
-
class="agrid-chart__slice-label"
|
|
10372
|
-
[attr.x]="s.labelX"
|
|
10373
|
-
[attr.y]="s.labelY"
|
|
10374
|
-
text-anchor="middle"
|
|
10375
|
-
dominant-baseline="middle"
|
|
10376
|
-
>{{ s.percentText }}</text>
|
|
10377
|
-
}
|
|
10378
|
-
}
|
|
10379
|
-
</svg>
|
|
10380
|
-
@if (showLegend() && layout().legend.length) {
|
|
10381
|
-
<ul class="agrid-chart__legend">
|
|
10382
|
-
@for (item of layout().legend; track $index) {
|
|
10383
|
-
<li>
|
|
10384
|
-
<span class="agrid-chart__swatch" [style.background-color]="item.color"></span>
|
|
10385
|
-
{{ item.name }}
|
|
10386
|
-
</li>
|
|
10387
|
-
}
|
|
10388
|
-
</ul>
|
|
10389
|
-
}
|
|
10390
|
-
`, isInline: true, styles: [":host{display:block;width:100%;font-family:inherit}.agrid-chart__svg{display:block}.agrid-chart__grid{stroke:var(--agrid-chart-grid, #e5e7eb);stroke-width:1}.agrid-chart__line{stroke-width:1.75;stroke-linejoin:round;stroke-linecap:round}.agrid-chart__slice{stroke:var(--agrid-chart-slice-stroke, #fff);stroke-width:1}.agrid-chart__axis{fill:var(--agrid-chart-axis, #6b7280);font-size:10px}.agrid-chart__slice-label{fill:#fff;font-size:10px;font-weight:600}.agrid-chart__legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin:6px 0 0;padding:0;list-style:none;font-size:12px;color:var(--agrid-chart-axis, #4b5563)}.agrid-chart__legend li{display:inline-flex;align-items:center;gap:5px}.agrid-chart__swatch{width:10px;height:10px;border-radius:2px;display:inline-block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11185
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AgridChartComponent, isStandalone: true, selector: "agrid-chart", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<svg class=\"agrid-chart__svg\" role=\"img\" [attr.width]=\"width()\" [attr.height]=\"height()\">\n @for (g of layout().gridlines; track $index) {\n <line class=\"agrid-chart__grid\" [attr.x1]=\"g.x1\" [attr.y1]=\"g.y1\" [attr.x2]=\"g.x2\" [attr.y2]=\"g.y2\" />\n }\n @for (a of layout().areas; track $index) {\n <path [attr.d]=\"a.d\" [attr.fill]=\"a.color\" fill-opacity=\"0.15\" />\n }\n @for (l of layout().lines; track $index) {\n <path class=\"agrid-chart__line\" fill=\"none\" [attr.d]=\"l.d\" [attr.stroke]=\"l.color\" />\n }\n @for (p of layout().points; track $index) {\n <circle [attr.cx]=\"p.x\" [attr.cy]=\"p.y\" r=\"2\" [attr.fill]=\"p.color\" />\n }\n @for (b of layout().bars; track $index) {\n <rect rx=\"1\" [attr.x]=\"b.x\" [attr.y]=\"b.y\" [attr.width]=\"b.width\" [attr.height]=\"b.height\" [attr.fill]=\"b.color\" />\n }\n @for (s of layout().slices; track $index) {\n <path class=\"agrid-chart__slice\" [attr.d]=\"s.d\" [attr.fill]=\"s.color\" />\n }\n @for (lbl of layout().axisLabels; track $index) {\n <text class=\"agrid-chart__axis\" [attr.x]=\"lbl.x\" [attr.y]=\"lbl.y\" [attr.text-anchor]=\"lbl.anchor\"\n [attr.dominant-baseline]=\"lbl.baseline\">{{ lbl.text }}</text>\n }\n @if (sliceLabels()) {\n @for (s of layout().slices; track $index) {\n <text class=\"agrid-chart__slice-label\" [attr.x]=\"s.labelX\" [attr.y]=\"s.labelY\" text-anchor=\"middle\"\n dominant-baseline=\"middle\">{{ s.percentText }}</text>\n }\n }\n</svg>\n\n@if (showLegend() && layout().legend.length) {\n<ul class=\"agrid-chart__legend\">\n @for (item of layout().legend; track $index) {\n <li>\n <span class=\"agrid-chart__swatch\" [style.background-color]=\"item.color\"></span>\n {{ item.name }}\n </li>\n }\n</ul>\n}", styles: [":host{display:block;width:100%;font-family:inherit}.agrid-chart__svg{display:block}.agrid-chart__grid{stroke:var(--agrid-chart-grid, #e5e7eb);stroke-width:1}.agrid-chart__line{stroke-width:1.75;stroke-linejoin:round;stroke-linecap:round}.agrid-chart__slice{stroke:var(--agrid-chart-slice-stroke, #fff);stroke-width:1}.agrid-chart__axis{fill:var(--agrid-chart-axis, #6b7280);font-size:10px}.agrid-chart__slice-label{fill:#fff;font-size:10px;font-weight:600}.agrid-chart__legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin:6px 0 0;padding:0;list-style:none;font-size:12px;color:var(--agrid-chart-axis, #4b5563)}.agrid-chart__legend li{display:inline-flex;align-items:center;gap:5px}.agrid-chart__swatch{width:10px;height:10px;border-radius:2px;display:inline-block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10391
11186
|
}
|
|
10392
11187
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AgridChartComponent, decorators: [{
|
|
10393
11188
|
type: Component,
|
|
10394
|
-
args: [{ selector: 'agrid-chart', changeDetection: ChangeDetectionStrategy.OnPush, template:
|
|
10395
|
-
<svg
|
|
10396
|
-
class="agrid-chart__svg"
|
|
10397
|
-
role="img"
|
|
10398
|
-
[attr.width]="width()"
|
|
10399
|
-
[attr.height]="height()"
|
|
10400
|
-
>
|
|
10401
|
-
@for (g of layout().gridlines; track $index) {
|
|
10402
|
-
<line class="agrid-chart__grid" [attr.x1]="g.x1" [attr.y1]="g.y1" [attr.x2]="g.x2" [attr.y2]="g.y2" />
|
|
10403
|
-
}
|
|
10404
|
-
@for (a of layout().areas; track $index) {
|
|
10405
|
-
<path [attr.d]="a.d" [attr.fill]="a.color" fill-opacity="0.15" />
|
|
10406
|
-
}
|
|
10407
|
-
@for (l of layout().lines; track $index) {
|
|
10408
|
-
<path
|
|
10409
|
-
class="agrid-chart__line"
|
|
10410
|
-
fill="none"
|
|
10411
|
-
[attr.d]="l.d"
|
|
10412
|
-
[attr.stroke]="l.color"
|
|
10413
|
-
/>
|
|
10414
|
-
}
|
|
10415
|
-
@for (p of layout().points; track $index) {
|
|
10416
|
-
<circle [attr.cx]="p.x" [attr.cy]="p.y" r="2" [attr.fill]="p.color" />
|
|
10417
|
-
}
|
|
10418
|
-
@for (b of layout().bars; track $index) {
|
|
10419
|
-
<rect rx="1" [attr.x]="b.x" [attr.y]="b.y" [attr.width]="b.width" [attr.height]="b.height" [attr.fill]="b.color" />
|
|
10420
|
-
}
|
|
10421
|
-
@for (s of layout().slices; track $index) {
|
|
10422
|
-
<path class="agrid-chart__slice" [attr.d]="s.d" [attr.fill]="s.color" />
|
|
10423
|
-
}
|
|
10424
|
-
@for (lbl of layout().axisLabels; track $index) {
|
|
10425
|
-
<text
|
|
10426
|
-
class="agrid-chart__axis"
|
|
10427
|
-
[attr.x]="lbl.x"
|
|
10428
|
-
[attr.y]="lbl.y"
|
|
10429
|
-
[attr.text-anchor]="lbl.anchor"
|
|
10430
|
-
[attr.dominant-baseline]="lbl.baseline"
|
|
10431
|
-
>{{ lbl.text }}</text>
|
|
10432
|
-
}
|
|
10433
|
-
@if (sliceLabels()) {
|
|
10434
|
-
@for (s of layout().slices; track $index) {
|
|
10435
|
-
<text
|
|
10436
|
-
class="agrid-chart__slice-label"
|
|
10437
|
-
[attr.x]="s.labelX"
|
|
10438
|
-
[attr.y]="s.labelY"
|
|
10439
|
-
text-anchor="middle"
|
|
10440
|
-
dominant-baseline="middle"
|
|
10441
|
-
>{{ s.percentText }}</text>
|
|
10442
|
-
}
|
|
10443
|
-
}
|
|
10444
|
-
</svg>
|
|
10445
|
-
@if (showLegend() && layout().legend.length) {
|
|
10446
|
-
<ul class="agrid-chart__legend">
|
|
10447
|
-
@for (item of layout().legend; track $index) {
|
|
10448
|
-
<li>
|
|
10449
|
-
<span class="agrid-chart__swatch" [style.background-color]="item.color"></span>
|
|
10450
|
-
{{ item.name }}
|
|
10451
|
-
</li>
|
|
10452
|
-
}
|
|
10453
|
-
</ul>
|
|
10454
|
-
}
|
|
10455
|
-
`, styles: [":host{display:block;width:100%;font-family:inherit}.agrid-chart__svg{display:block}.agrid-chart__grid{stroke:var(--agrid-chart-grid, #e5e7eb);stroke-width:1}.agrid-chart__line{stroke-width:1.75;stroke-linejoin:round;stroke-linecap:round}.agrid-chart__slice{stroke:var(--agrid-chart-slice-stroke, #fff);stroke-width:1}.agrid-chart__axis{fill:var(--agrid-chart-axis, #6b7280);font-size:10px}.agrid-chart__slice-label{fill:#fff;font-size:10px;font-weight:600}.agrid-chart__legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin:6px 0 0;padding:0;list-style:none;font-size:12px;color:var(--agrid-chart-axis, #4b5563)}.agrid-chart__legend li{display:inline-flex;align-items:center;gap:5px}.agrid-chart__swatch{width:10px;height:10px;border-radius:2px;display:inline-block}\n"] }]
|
|
11189
|
+
args: [{ selector: 'agrid-chart', changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg class=\"agrid-chart__svg\" role=\"img\" [attr.width]=\"width()\" [attr.height]=\"height()\">\n @for (g of layout().gridlines; track $index) {\n <line class=\"agrid-chart__grid\" [attr.x1]=\"g.x1\" [attr.y1]=\"g.y1\" [attr.x2]=\"g.x2\" [attr.y2]=\"g.y2\" />\n }\n @for (a of layout().areas; track $index) {\n <path [attr.d]=\"a.d\" [attr.fill]=\"a.color\" fill-opacity=\"0.15\" />\n }\n @for (l of layout().lines; track $index) {\n <path class=\"agrid-chart__line\" fill=\"none\" [attr.d]=\"l.d\" [attr.stroke]=\"l.color\" />\n }\n @for (p of layout().points; track $index) {\n <circle [attr.cx]=\"p.x\" [attr.cy]=\"p.y\" r=\"2\" [attr.fill]=\"p.color\" />\n }\n @for (b of layout().bars; track $index) {\n <rect rx=\"1\" [attr.x]=\"b.x\" [attr.y]=\"b.y\" [attr.width]=\"b.width\" [attr.height]=\"b.height\" [attr.fill]=\"b.color\" />\n }\n @for (s of layout().slices; track $index) {\n <path class=\"agrid-chart__slice\" [attr.d]=\"s.d\" [attr.fill]=\"s.color\" />\n }\n @for (lbl of layout().axisLabels; track $index) {\n <text class=\"agrid-chart__axis\" [attr.x]=\"lbl.x\" [attr.y]=\"lbl.y\" [attr.text-anchor]=\"lbl.anchor\"\n [attr.dominant-baseline]=\"lbl.baseline\">{{ lbl.text }}</text>\n }\n @if (sliceLabels()) {\n @for (s of layout().slices; track $index) {\n <text class=\"agrid-chart__slice-label\" [attr.x]=\"s.labelX\" [attr.y]=\"s.labelY\" text-anchor=\"middle\"\n dominant-baseline=\"middle\">{{ s.percentText }}</text>\n }\n }\n</svg>\n\n@if (showLegend() && layout().legend.length) {\n<ul class=\"agrid-chart__legend\">\n @for (item of layout().legend; track $index) {\n <li>\n <span class=\"agrid-chart__swatch\" [style.background-color]=\"item.color\"></span>\n {{ item.name }}\n </li>\n }\n</ul>\n}", styles: [":host{display:block;width:100%;font-family:inherit}.agrid-chart__svg{display:block}.agrid-chart__grid{stroke:var(--agrid-chart-grid, #e5e7eb);stroke-width:1}.agrid-chart__line{stroke-width:1.75;stroke-linejoin:round;stroke-linecap:round}.agrid-chart__slice{stroke:var(--agrid-chart-slice-stroke, #fff);stroke-width:1}.agrid-chart__axis{fill:var(--agrid-chart-axis, #6b7280);font-size:10px}.agrid-chart__slice-label{fill:#fff;font-size:10px;font-weight:600}.agrid-chart__legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin:6px 0 0;padding:0;list-style:none;font-size:12px;color:var(--agrid-chart-axis, #4b5563)}.agrid-chart__legend li{display:inline-flex;align-items:center;gap:5px}.agrid-chart__swatch{width:10px;height:10px;border-radius:2px;display:inline-block}\n"] }]
|
|
10456
11190
|
}], ctorParameters: () => [], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: true }] }] } });
|
|
10457
11191
|
|
|
10458
11192
|
/**
|
|
10459
11193
|
* Generated bundle index. Do not edit.
|
|
10460
11194
|
*/
|
|
10461
11195
|
|
|
10462
|
-
export { AGRID_CHART_PALETTE, AGRID_EDITOR_CONTEXT, AGRID_LOCALE_TEXT, AGRID_RENDERER_CONTEXT, AgridBrowserAdapter, AgridChartComponent, AgridChartProvider, AgridComponent, AgridControl, AgridDataSource, AgridPageSelectorComponent, AgridProvider, AgridServerSideRowModel, AgridTreeComponent, AgridTreeProvider, ColDefAutoSize, buildChart };
|
|
11196
|
+
export { AGRID_CHART_PALETTE, AGRID_EDITOR_CONTEXT, AGRID_FILTER_CONTEXT, AGRID_LOCALE_TEXT, AGRID_RENDERER_CONTEXT, AgridBrowserAdapter, AgridChartComponent, AgridChartProvider, AgridComponent, AgridControl, AgridDataSource, AgridPageSelectorComponent, AgridProvider, AgridServerSideRowModel, AgridTreeComponent, AgridTreeProvider, ColDefAutoSize, buildChart };
|
|
10463
11197
|
//# sourceMappingURL=thkl-agrid.mjs.map
|