@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.
@@ -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(() => resolveCellSpanLayout(this.paneColumns(), this.paneColumns().indexOf(this.col()), this.row(), this.rowIndex()), ...(ngDevMode ? [{ debugName: "cellSpanLayout" }] : /* istanbul ignore next */ []));
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
- return vals.map(v => typeof v === 'string'
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
- const viewportWidth = this.opts.viewportWidth();
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
- return this.items().filter(item => !search || item.label.toLowerCase().includes(search));
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
- control.setSelectedValues(field, control.getFilter(field).selectedValues === null ? [] : null);
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
- control.setSelectedValues(field, next.length === allValues.length ? null : next);
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
- arr.splice(to > from ? to - 1 : to, 0, item);
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
- return getDisplayForField(col, this.opts.dataSource().rows()[idx]?.[col.field], this.opts.locale());
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
- if (oldValue === newValue)
3998
+ const storedValue = col.type === 'number'
3999
+ ? coerceNumberInputValue(newValue)
4000
+ : newValue;
4001
+ if (oldValue === storedValue)
3594
4002
  return true;
3595
- const message = col.validate?.(newValue, row) ?? null;
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: newValue, message });
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]: newValue });
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 all cached blocks while preserving a known total row count. */
5915
- refresh() {
5916
- this.reset();
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
- return sortEntries.length
6077
- ? applySortToIndices(rows, indices, sortEntries, colMap, this.opts.locale())
6078
- : indices;
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
- showControlColumn = computed(() => this.provider().showControlColumn || this.enableRowMarking() || this.masterDetail(), ...(ngDevMode ? [{ debugName: "showControlColumn" }] : /* istanbul ignore next */ []));
7382
- controlColumnWidth = computed(() => this.enableRowMarking() ? 48 : 24, ...(ngDevMode ? [{ debugName: "controlColumnWidth" }] : /* istanbul ignore next */ []));
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