@thkl/agrid 0.1.0 → 0.1.3

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.
@@ -401,7 +401,7 @@ class AgridCellComponent {
401
401
  } @else {
402
402
  <span class="ag-cell-value">{{ displayValue() }}</span>
403
403
  }
404
- `, isInline: true, styles: [":host{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(.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-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
404
+ `, 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-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
405
405
  }
406
406
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AgridCellComponent, decorators: [{
407
407
  type: Component,
@@ -439,7 +439,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
439
439
  } @else {
440
440
  <span class="ag-cell-value">{{ displayValue() }}</span>
441
441
  }
442
- `, styles: [":host{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(.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-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}\n"] }]
442
+ `, 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-input{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 6px;box-sizing:border-box;background:transparent}.ag-cell-select{width:100%;height:100%;border:none;outline:none;font:inherit;padding:0 2px;box-sizing:border-box;background:transparent;cursor:pointer}\n"] }]
443
443
  }], ctorParameters: () => [], propDecorators: { col: [{ type: i0.Input, args: [{ isSignal: true, alias: "col", required: true }] }], 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 }] }], 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 }] }], seedChar: [{ type: i0.Input, args: [{ isSignal: true, alias: "seedChar", required: false }] }], activate: [{ type: i0.Output, args: ["activate"] }], startEdit: [{ type: i0.Output, args: ["startEdit"] }], draftChange: [{ type: i0.Output, args: ["draftChange"] }], inputEl: [{ type: i0.ViewChild, args: ['editInput', { isSignal: true }] }], selectEl: [{ type: i0.ViewChild, args: ['editSelect', { isSignal: true }] }] } });
444
444
 
445
445
  /** Guarded access to browser-only APIs used by the grid. @internal */
@@ -565,30 +565,48 @@ class AgridClipboardHandler {
565
565
  getSelectedTsv() {
566
566
  const bounds = this.getVisibleRangeBounds();
567
567
  const selected = this.opts.selectedCell();
568
- if (!bounds && !selected)
568
+ const marked = this.opts.markedRowIndices();
569
+ if (!bounds && !selected && marked.size === 0)
569
570
  return '';
570
- const rowStart = bounds?.rowStart ?? this.findDisplayIndex(selected.rowIndex);
571
+ const rowStart = bounds?.rowStart ?? (selected ? this.findDisplayIndex(selected.rowIndex) : -1);
571
572
  const rowEnd = bounds?.rowEnd ?? rowStart;
572
- const colStart = bounds?.colStart ?? selected.colIndex;
573
- const colEnd = bounds?.colEnd ?? selected.colIndex;
573
+ const colStart = bounds?.colStart ?? selected?.colIndex ?? 0;
574
+ const colEnd = bounds?.colEnd ?? selected?.colIndex
575
+ ?? this.opts.visibleColDefs().length - 1;
574
576
  const rows = this.opts.filteredItems();
575
577
  const cols = this.opts.visibleColDefs();
578
+ const dataRows = this.opts.dataSource().rows();
576
579
  const lines = [];
577
- for (let displayIndex = rowStart; displayIndex <= rowEnd; displayIndex++) {
578
- const item = rows[displayIndex];
579
- if (!isDataRowItem(item))
580
- continue;
581
- const cells = [];
582
- for (let colIndex = colStart; colIndex <= colEnd; colIndex++) {
583
- const col = cols[colIndex];
584
- if (!col)
580
+ const copiedIndices = new Set();
581
+ if (rowStart >= 0) {
582
+ for (let displayIndex = rowStart; displayIndex <= rowEnd; displayIndex++) {
583
+ const item = rows[displayIndex];
584
+ if (!isDataRowItem(item))
585
585
  continue;
586
- cells.push(this.escapeTsvValue(getDisplayForField(col, item.row[col.field], this.opts.locale())));
586
+ lines.push(this.serializeRow(item.row, cols, colStart, colEnd));
587
+ copiedIndices.add(item.originalIndex);
587
588
  }
588
- lines.push(cells.join('\t'));
589
+ }
590
+ for (const originalIndex of [...marked].sort((a, b) => a - b)) {
591
+ if (copiedIndices.has(originalIndex))
592
+ continue;
593
+ const row = dataRows[originalIndex];
594
+ if (!row)
595
+ continue;
596
+ lines.push(this.serializeRow(row, cols, colStart, colEnd));
589
597
  }
590
598
  return lines.join('\n');
591
599
  }
600
+ serializeRow(row, cols, colStart, colEnd) {
601
+ const cells = [];
602
+ for (let colIndex = colStart; colIndex <= colEnd; colIndex++) {
603
+ const col = cols[colIndex];
604
+ if (!col)
605
+ continue;
606
+ cells.push(this.escapeTsvValue(getDisplayForField(col, row[col.field], this.opts.locale())));
607
+ }
608
+ return cells.join('\t');
609
+ }
592
610
  /** Applies delimited text to editable cells beginning at the active selection. */
593
611
  pasteTextAtSelection(text) {
594
612
  const bounds = this.getActiveSelectionBounds();
@@ -808,20 +826,30 @@ class AgridColumnLayoutModel {
808
826
  hasPinnedPane = computed(() => this.opts.showControlColumn() || this.pinnedColDefs().length > 0, ...(ngDevMode ? [{ debugName: "hasPinnedPane" }] : /* istanbul ignore next */ []));
809
827
  hasRightPinnedPane = computed(() => this.rightPinnedColDefs().length > 0, ...(ngDevMode ? [{ debugName: "hasRightPinnedPane" }] : /* istanbul ignore next */ []));
810
828
  hasFilterableColumns = computed(() => this.visibleColDefs().some(col => col.filterable), ...(ngDevMode ? [{ debugName: "hasFilterableColumns" }] : /* istanbul ignore next */ []));
829
+ hasHeaderGroups = computed(() => this.visibleColDefs().some(col => this.groupLabel(col.group) !== null), ...(ngDevMode ? [{ debugName: "hasHeaderGroups" }] : /* istanbul ignore next */ []));
830
+ pinnedHeaderGroupRuns = computed(() => this.buildHeaderGroupRuns(this.pinnedColDefs(), 'left'), ...(ngDevMode ? [{ debugName: "pinnedHeaderGroupRuns" }] : /* istanbul ignore next */ []));
831
+ scrollableHeaderGroupRuns = computed(() => this.buildHeaderGroupRuns(this.scrollableColDefs(), 'center'), ...(ngDevMode ? [{ debugName: "scrollableHeaderGroupRuns" }] : /* istanbul ignore next */ []));
832
+ rightHeaderGroupRuns = computed(() => this.buildHeaderGroupRuns(this.rightPinnedColDefs(), 'right'), ...(ngDevMode ? [{ debugName: "rightHeaderGroupRuns" }] : /* istanbul ignore next */ []));
811
833
  gridTemplateColumns = computed(() => {
812
834
  const columns = this.widthTokens(this.visibleColDefs());
813
- return this.opts.showControlColumn() ? `24px ${columns}` : columns;
835
+ return this.opts.showControlColumn()
836
+ ? `${this.opts.controlColumnWidth()}px ${columns}`
837
+ : columns;
814
838
  }, ...(ngDevMode ? [{ debugName: "gridTemplateColumns" }] : /* istanbul ignore next */ []));
815
839
  pinnedGridTemplateColumns = computed(() => {
816
840
  const columns = this.widthTokens(this.pinnedColDefs());
817
- if (this.opts.showControlColumn())
818
- return columns ? `24px ${columns}` : '24px';
841
+ if (this.opts.showControlColumn()) {
842
+ const controlWidth = `${this.opts.controlColumnWidth()}px`;
843
+ return columns ? `${controlWidth} ${columns}` : controlWidth;
844
+ }
819
845
  return columns;
820
846
  }, ...(ngDevMode ? [{ debugName: "pinnedGridTemplateColumns" }] : /* istanbul ignore next */ []));
821
847
  scrollableGridTemplateColumns = computed(() => this.widthTokens(this.scrollableColDefs()), ...(ngDevMode ? [{ debugName: "scrollableGridTemplateColumns" }] : /* istanbul ignore next */ []));
822
848
  rightGridTemplateColumns = computed(() => this.widthTokens(this.rightPinnedColDefs()), ...(ngDevMode ? [{ debugName: "rightGridTemplateColumns" }] : /* istanbul ignore next */ []));
823
- totalWidth = computed(() => this.width(this.visibleColDefs()) + (this.opts.showControlColumn() ? 24 : 0), ...(ngDevMode ? [{ debugName: "totalWidth" }] : /* istanbul ignore next */ []));
824
- pinnedPaneWidth = computed(() => this.width(this.pinnedColDefs()) + (this.opts.showControlColumn() ? 24 : 0), ...(ngDevMode ? [{ debugName: "pinnedPaneWidth" }] : /* istanbul ignore next */ []));
849
+ totalWidth = computed(() => this.width(this.visibleColDefs())
850
+ + (this.opts.showControlColumn() ? this.opts.controlColumnWidth() : 0), ...(ngDevMode ? [{ debugName: "totalWidth" }] : /* istanbul ignore next */ []));
851
+ pinnedPaneWidth = computed(() => this.width(this.pinnedColDefs())
852
+ + (this.opts.showControlColumn() ? this.opts.controlColumnWidth() : 0), ...(ngDevMode ? [{ debugName: "pinnedPaneWidth" }] : /* istanbul ignore next */ []));
825
853
  rightPinnedPaneWidth = computed(() => this.width(this.rightPinnedColDefs()), ...(ngDevMode ? [{ debugName: "rightPinnedPaneWidth" }] : /* istanbul ignore next */ []));
826
854
  scrollableTotalWidth = computed(() => this.width(this.scrollableColDefs()), ...(ngDevMode ? [{ debugName: "scrollableTotalWidth" }] : /* istanbul ignore next */ []));
827
855
  width(columns) {
@@ -830,6 +858,32 @@ class AgridColumnLayoutModel {
830
858
  widthTokens(columns) {
831
859
  return columns.map(col => this.opts.getColumnWidthToken(col)).join(' ');
832
860
  }
861
+ buildHeaderGroupRuns(columns, pane) {
862
+ const runs = [];
863
+ for (const col of columns) {
864
+ const label = this.groupLabel(col.group);
865
+ const id = label === null ? null : col.group ?? null;
866
+ const previous = runs[runs.length - 1];
867
+ if (id !== null && previous?.id === id) {
868
+ previous.fields.push(col.field);
869
+ previous.span++;
870
+ continue;
871
+ }
872
+ runs.push({
873
+ key: `${pane}:${col.field}`,
874
+ id,
875
+ label: label ?? '',
876
+ fields: [col.field],
877
+ span: 1,
878
+ });
879
+ }
880
+ return runs;
881
+ }
882
+ groupLabel(groupId) {
883
+ if (!groupId)
884
+ return null;
885
+ return this.opts.headerGroups().find(group => group.id === groupId)?.label ?? null;
886
+ }
833
887
  }
834
888
 
835
889
  /** Built-in English and German grid translations. */
@@ -855,6 +909,9 @@ const AGRID_LOCALE_TEXT = {
855
909
  hiddenColumn: '(hidden)',
856
910
  copyCellValue: 'Copy cell',
857
911
  copyRow: 'Copy row',
912
+ confirmDeleteRow: 'Sure to delete?',
913
+ confirmNo: 'No',
914
+ confirmYes: 'Yes',
858
915
  deleteRow: 'Delete row',
859
916
  filterPlaceholder: 'Filter...',
860
917
  findPlaceholder: 'Find',
@@ -866,6 +923,7 @@ const AGRID_LOCALE_TEXT = {
866
923
  insertRowBelow: 'Insert row below',
867
924
  lastPage: 'Last page',
868
925
  loading: 'Loading...',
926
+ markRow: 'Mark row for copying',
869
927
  next: 'Next',
870
928
  noRows: 'No rows to display',
871
929
  pagination: 'Pagination',
@@ -905,6 +963,9 @@ const AGRID_LOCALE_TEXT = {
905
963
  hiddenColumn: '(ausgeblendet)',
906
964
  copyCellValue: 'Zelle kopieren',
907
965
  copyRow: 'Zeile kopieren',
966
+ confirmDeleteRow: 'Wirklich löschen?',
967
+ confirmNo: 'Nein',
968
+ confirmYes: 'Ja',
908
969
  deleteRow: 'Zeile löschen',
909
970
  filterPlaceholder: 'Filtern...',
910
971
  findPlaceholder: 'Suchen',
@@ -916,6 +977,7 @@ const AGRID_LOCALE_TEXT = {
916
977
  insertRowBelow: 'Zeile darunter einfügen',
917
978
  lastPage: 'Letzte Seite',
918
979
  loading: 'Wird geladen...',
980
+ markRow: 'Zeile zum Kopieren markieren',
919
981
  next: 'Weiter',
920
982
  noRows: 'Keine Zeilen vorhanden',
921
983
  pagination: 'Seitennavigation',
@@ -1361,11 +1423,19 @@ class AgridColumnMenuController {
1361
1423
  class AgridColumnReorderController {
1362
1424
  opts;
1363
1425
  browser;
1364
- dragField = signal(null, ...(ngDevMode ? [{ debugName: "dragField" }] : /* istanbul ignore next */ []));
1426
+ dragFields = signal([], ...(ngDevMode ? [{ debugName: "dragFields" }] : /* istanbul ignore next */ []));
1365
1427
  dragOverField = signal(null, ...(ngDevMode ? [{ debugName: "dragOverField" }] : /* istanbul ignore next */ []));
1366
1428
  dragInsertBefore = signal(true, ...(ngDevMode ? [{ debugName: "dragInsertBefore" }] : /* istanbul ignore next */ []));
1367
- dragStartField = null;
1429
+ preview = signal(null, ...(ngDevMode ? [{ debugName: "preview" }] : /* istanbul ignore next */ []));
1430
+ dragStartFields = [];
1431
+ dragLabel = '';
1368
1432
  dragStartX = 0;
1433
+ dragStartY = 0;
1434
+ pointerOffsetX = 0;
1435
+ pointerOffsetY = 0;
1436
+ draggedWidth = 0;
1437
+ draggedHeight = 0;
1438
+ dropTargets = [];
1369
1439
  constructor(opts, destroyRef, browser = new AgridBrowserAdapter()) {
1370
1440
  this.opts = opts;
1371
1441
  this.browser = browser;
@@ -1373,36 +1443,92 @@ class AgridColumnReorderController {
1373
1443
  }
1374
1444
  /** Arms a column reorder gesture for an unlocked header. */
1375
1445
  start(event, field) {
1446
+ const col = this.opts.getColDef(field);
1447
+ this.startFields(event, [field], col?.header ?? field);
1448
+ }
1449
+ /** Arms a grouped-header reorder gesture for a contiguous field segment. */
1450
+ startGroup(event, fields, label) {
1451
+ this.startFields(event, fields, label);
1452
+ }
1453
+ startFields(event, fields, label) {
1376
1454
  if (!this.opts.control() || event.button !== 0)
1377
1455
  return;
1378
- if (this.opts.getColDef(field)?.locked)
1456
+ if (fields.length === 0 || fields.some(field => this.opts.getColDef(field)?.locked))
1379
1457
  return;
1380
- this.dragStartField = field;
1458
+ const header = event.currentTarget;
1459
+ const rect = header?.getBoundingClientRect();
1460
+ this.dragStartFields = [...fields];
1461
+ this.dragLabel = label;
1381
1462
  this.dragStartX = event.clientX;
1463
+ this.dragStartY = event.clientY;
1464
+ this.draggedWidth = rect?.width ?? 0;
1465
+ this.draggedHeight = rect?.height ?? 32;
1466
+ this.pointerOffsetX = rect ? event.clientX - rect.left : 0;
1467
+ this.pointerOffsetY = rect ? event.clientY - rect.top : 0;
1468
+ this.dropTargets = this.captureDropTargets(header);
1382
1469
  this.browser.addDocumentListener('pointermove', this.dragMove);
1383
1470
  this.browser.addDocumentListener('pointerup', this.dragUp);
1384
1471
  this.browser.addDocumentListener('pointercancel', this.dragCancel);
1385
1472
  }
1386
1473
  /** Returns whether the field is currently being dragged. */
1387
1474
  isDragging(field) {
1388
- return this.dragField() === field;
1475
+ return this.dragFields().includes(field);
1389
1476
  }
1390
1477
  /** Returns the active drop-indicator side for a field. */
1391
1478
  getDropSide(field) {
1392
- if (this.dragOverField() !== field || this.dragField() === field)
1479
+ if (this.dragOverField() !== field || this.dragFields().includes(field))
1393
1480
  return null;
1394
1481
  return this.dragInsertBefore() ? 'before' : 'after';
1395
1482
  }
1483
+ /** Horizontal translation used to animate headers away from the pending insertion gap. */
1484
+ getHeaderOffset(field) {
1485
+ const movingFields = this.dragFields();
1486
+ const overField = this.dragOverField();
1487
+ if (movingFields.length === 0 || !overField || movingFields.includes(field)
1488
+ || this.draggedWidth <= 0)
1489
+ return 0;
1490
+ const fields = this.opts.visibleColDefs().map(col => col.field);
1491
+ const fromIndex = fields.findIndex(value => movingFields.includes(value));
1492
+ const remaining = fields.filter(value => !movingFields.includes(value));
1493
+ const overIndex = remaining.indexOf(overField);
1494
+ const fieldIndex = remaining.indexOf(field);
1495
+ if (fromIndex < 0 || overIndex < 0 || fieldIndex < 0)
1496
+ return 0;
1497
+ const insertionIndex = overIndex + (this.dragInsertBefore() ? 0 : 1);
1498
+ if (insertionIndex < fromIndex && fieldIndex >= insertionIndex && fieldIndex < fromIndex) {
1499
+ return this.draggedWidth;
1500
+ }
1501
+ if (insertionIndex > fromIndex && fieldIndex >= fromIndex && fieldIndex < insertionIndex) {
1502
+ return -this.draggedWidth;
1503
+ }
1504
+ return 0;
1505
+ }
1396
1506
  dragMove = (event) => {
1397
- if (!this.dragStartField)
1507
+ if (this.dragStartFields.length === 0)
1398
1508
  return;
1399
- if (this.dragField() === null) {
1509
+ if (this.dragFields().length === 0) {
1400
1510
  if (Math.abs(event.clientX - this.dragStartX) < 5)
1401
1511
  return;
1402
- this.dragField.set(this.dragStartField);
1512
+ this.dragFields.set([...this.dragStartFields]);
1513
+ this.preview.set({
1514
+ field: this.dragStartFields[0],
1515
+ fields: [...this.dragStartFields],
1516
+ label: this.dragLabel,
1517
+ x: event.clientX - this.pointerOffsetX,
1518
+ y: event.clientY - this.pointerOffsetY,
1519
+ width: this.draggedWidth,
1520
+ height: this.draggedHeight,
1521
+ });
1522
+ }
1523
+ else {
1524
+ this.preview.update(preview => preview ? {
1525
+ ...preview,
1526
+ x: event.clientX - this.pointerOffsetX,
1527
+ y: event.clientY - this.pointerOffsetY,
1528
+ } : null);
1403
1529
  }
1404
1530
  const hovered = this.getHoveredHeaderCell(event.clientX, event.clientY);
1405
- if (hovered && hovered.field !== this.dragField()) {
1531
+ if (hovered && !this.dragFields().includes(hovered.field)) {
1406
1532
  this.dragOverField.set(hovered.field);
1407
1533
  this.dragInsertBefore.set(hovered.insertBefore);
1408
1534
  }
@@ -1412,38 +1538,58 @@ class AgridColumnReorderController {
1412
1538
  };
1413
1539
  dragUp = () => {
1414
1540
  this.removeListeners();
1415
- const from = this.dragField();
1541
+ const from = this.dragFields();
1416
1542
  const to = this.dragOverField();
1417
- if (from && to) {
1418
- this.opts.control()?.moveColumn(this.opts.visibleColDefs().map(col => col.field), from, to, this.dragInsertBefore());
1543
+ if (from.length > 0 && to) {
1544
+ this.opts.control()?.moveColumns(this.opts.visibleColDefs().map(col => col.field), from, to, this.dragInsertBefore());
1419
1545
  }
1420
- this.dragField.set(null);
1546
+ this.dragFields.set([]);
1421
1547
  this.dragOverField.set(null);
1422
1548
  this.dragInsertBefore.set(true);
1423
- this.dragStartField = null;
1549
+ this.preview.set(null);
1550
+ this.dragStartFields = [];
1551
+ this.dragLabel = '';
1552
+ this.dropTargets = [];
1424
1553
  };
1425
1554
  dragCancel = () => this.cancel();
1426
1555
  cancel() {
1427
1556
  this.removeListeners();
1428
- this.dragField.set(null);
1557
+ this.dragFields.set([]);
1429
1558
  this.dragOverField.set(null);
1430
1559
  this.dragInsertBefore.set(true);
1431
- this.dragStartField = null;
1560
+ this.preview.set(null);
1561
+ this.dragStartFields = [];
1562
+ this.dragLabel = '';
1563
+ this.dropTargets = [];
1432
1564
  }
1433
1565
  removeListeners() {
1434
1566
  this.browser.removeDocumentListener('pointermove', this.dragMove);
1435
1567
  this.browser.removeDocumentListener('pointerup', this.dragUp);
1436
1568
  this.browser.removeDocumentListener('pointercancel', this.dragCancel);
1437
1569
  }
1438
- getHoveredHeaderCell(x, y) {
1439
- for (const el of this.browser.elementsFromPoint(x, y)) {
1440
- const headerEl = el.closest('.ag-header-cell[data-col-field]');
1441
- if (!headerEl?.dataset['colField'])
1442
- continue;
1443
- const rect = headerEl.getBoundingClientRect();
1444
- return { field: headerEl.dataset['colField'], insertBefore: x < rect.left + rect.width / 2 };
1445
- }
1446
- return null;
1570
+ getHoveredHeaderCell(x, _y) {
1571
+ const target = this.dropTargets.find(rect => x >= rect.left && x <= rect.right);
1572
+ return target
1573
+ ? { field: target.field, insertBefore: x < target.left + (target.right - target.left) / 2 }
1574
+ : null;
1575
+ }
1576
+ captureDropTargets(header) {
1577
+ const root = header?.closest('.ag-wrapper') ?? header?.ownerDocument;
1578
+ if (!root)
1579
+ return [];
1580
+ return [...root.querySelectorAll('.ag-header-cell[data-col-field]')]
1581
+ .map(element => {
1582
+ const field = element.dataset['colField'];
1583
+ const rect = element.getBoundingClientRect();
1584
+ return field ? {
1585
+ field,
1586
+ left: rect.left,
1587
+ right: rect.right,
1588
+ top: rect.top,
1589
+ bottom: rect.bottom,
1590
+ } : null;
1591
+ })
1592
+ .filter((target) => target !== null);
1447
1593
  }
1448
1594
  }
1449
1595
 
@@ -2150,6 +2296,12 @@ class AgridNavigationController {
2150
2296
  this.opts.cancelEdit();
2151
2297
  this.addRowAndSelect();
2152
2298
  }
2299
+ /** Clears cell and range navigation when focus moves to a grid control. */
2300
+ deactivateCell() {
2301
+ this.opts.cancelEdit();
2302
+ this.opts.selectedCell.set(null);
2303
+ this.opts.selectedRange.set(null);
2304
+ }
2153
2305
  /** Inserts an initialized blank row and emits the preparation callback. */
2154
2306
  insertRowAt(atIndex) {
2155
2307
  const emptyRow = this.buildEmptyRow();
@@ -2158,7 +2310,7 @@ class AgridNavigationController {
2158
2310
  }
2159
2311
  /** Handles grid-level navigation, editing, history, find, and add-row shortcuts. */
2160
2312
  handleKeyDown(event) {
2161
- if (event.target?.closest('.ag-sidebar'))
2313
+ if (event.target?.closest('.ag-sidebar, .ag-filter-input, .ag-filter-menu'))
2162
2314
  return;
2163
2315
  if ((event.ctrlKey || event.metaKey) && !event.altKey && event.key.toLowerCase() === 'f') {
2164
2316
  event.preventDefault();
@@ -2553,18 +2705,23 @@ class AgridControl {
2553
2705
  * operation works correctly whether or not an order has been set before.
2554
2706
  */
2555
2707
  moveColumn(currentVisibleOrder, fromField, toField, insertBefore) {
2708
+ this.moveColumns(currentVisibleOrder, [fromField], toField, insertBefore);
2709
+ }
2710
+ /**
2711
+ * Move an ordered block of fields to a new position relative to `toField`.
2712
+ * Fields absent from `currentVisibleOrder` are ignored.
2713
+ */
2714
+ moveColumns(currentVisibleOrder, fromFields, toField, insertBefore) {
2556
2715
  const order = [...currentVisibleOrder];
2557
- const fromIdx = order.indexOf(fromField);
2558
- if (fromIdx === -1)
2716
+ const moving = order.filter(field => fromFields.includes(field));
2717
+ if (moving.length === 0 || moving.includes(toField))
2559
2718
  return;
2560
- order.splice(fromIdx, 1);
2561
- const toIdx = order.indexOf(toField);
2562
- if (toIdx === -1) {
2563
- this._columnOrder.set(order);
2719
+ const remaining = order.filter(field => !moving.includes(field));
2720
+ const toIdx = remaining.indexOf(toField);
2721
+ if (toIdx === -1)
2564
2722
  return;
2565
- }
2566
- order.splice(insertBefore ? toIdx : toIdx + 1, 0, fromField);
2567
- this._columnOrder.set(order);
2723
+ remaining.splice(insertBefore ? toIdx : toIdx + 1, 0, ...moving);
2724
+ this._columnOrder.set(remaining);
2568
2725
  }
2569
2726
  // ── Pinned columns ────────────────────────────────────────────────────────
2570
2727
  /** Reactive set of field names currently pinned to the left edge. */
@@ -3021,6 +3178,8 @@ class AgridProvider {
3021
3178
  control;
3022
3179
  /** Reactive column definitions in display order. */
3023
3180
  columns;
3181
+ /** Header-group labels referenced by column definitions. */
3182
+ headerGroups;
3024
3183
  /** Shared grid options such as locale. */
3025
3184
  options;
3026
3185
  _localizations = new Map();
@@ -3050,6 +3209,8 @@ class AgridProvider {
3050
3209
  allowAddRows;
3051
3210
  /** Whether the control column is rendered. */
3052
3211
  showControlColumn;
3212
+ /** Whether rows can be marked for inclusion in clipboard copies. */
3213
+ enableRowMarking;
3053
3214
  /** Whether the sidebar is available. */
3054
3215
  showSidebar;
3055
3216
  /** Whether selecting a row automatically opens its detail panel. */
@@ -3072,6 +3233,10 @@ class AgridProvider {
3072
3233
  cellMenuItems;
3073
3234
  /** Whether alternating data rows receive stripe styling. */
3074
3235
  zebraStripes;
3236
+ /** Whether committed cell changes receive a visual marker. */
3237
+ showChangedCellIndicator;
3238
+ /** Whether grid row-delete actions require in-row confirmation. */
3239
+ confirmRowDelete;
3075
3240
  /** Optional empty-state text override. */
3076
3241
  emptyText;
3077
3242
  /** Whether edits are restricted to the sidebar editor. */
@@ -3086,12 +3251,14 @@ class AgridProvider {
3086
3251
  this.datasource = config.datasource ?? new AgridDataSource([]);
3087
3252
  this.control = config.control ?? new AgridControl({ allowRowReorder: true });
3088
3253
  this.columns = signal(config.columns ?? [], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
3254
+ this.headerGroups = config.headerGroups ?? [];
3089
3255
  this.rowHeight = config.rowHeight ?? 32;
3090
3256
  this.minHeight = config.minHeight;
3091
3257
  this.maxHeight = config.maxHeight;
3092
3258
  this.allowAddRows = config.allowAddRows ?? false;
3093
3259
  this.autoAddRows = signal(config.autoAddRows ?? false, ...(ngDevMode ? [{ debugName: "autoAddRows" }] : /* istanbul ignore next */ []));
3094
3260
  this.showControlColumn = config.showControlColumn ?? false;
3261
+ this.enableRowMarking = config.enableRowMarking ?? false;
3095
3262
  this.showSidebar = config.showSidebar ?? false;
3096
3263
  this.autoOpenDetail = config.autoOpenDetail ?? false;
3097
3264
  this.serverSideFiltering = config.serverSideFiltering ?? false;
@@ -3102,6 +3269,8 @@ class AgridProvider {
3102
3269
  this.groupActions = config.groupActions ?? [];
3103
3270
  this.cellMenuItems = config.cellMenuItems ?? [];
3104
3271
  this.zebraStripes = config.zebraStripes ?? false;
3272
+ this.showChangedCellIndicator = config.showChangedCellIndicator ?? false;
3273
+ this.confirmRowDelete = config.confirmRowDelete ?? false;
3105
3274
  this.emptyText = config.emptyText;
3106
3275
  this.loading = signal(config.loading ?? false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
3107
3276
  this.readonlyGrid = signal(config.readonly ?? false, ...(ngDevMode ? [{ debugName: "readonlyGrid" }] : /* istanbul ignore next */ []));
@@ -3617,19 +3786,36 @@ class AgridRowController {
3617
3786
  closeCellContextMenu() {
3618
3787
  this.cellContextMenu.set(null);
3619
3788
  }
3620
- /** Copies a cell's formatted display value to the clipboard. */
3621
- copyCellToClipboard(value, col) {
3622
- void this.browser.writeClipboard(getDisplayForField(col, value));
3789
+ /** Copies a cell plus the same field from marked rows to the clipboard. */
3790
+ copyCellToClipboard(originalIndex, col) {
3791
+ const rows = this.opts.dataSource().rows();
3792
+ const text = this.copyIndices(originalIndex)
3793
+ .map(index => getDisplayForField(col, rows[index]?.[col.field], this.opts.locale()))
3794
+ .join('\n');
3795
+ void this.browser.writeClipboard(text);
3623
3796
  this.closeCellContextMenu();
3624
3797
  }
3625
- /** Copies the visible values of a row as tab-separated text. */
3626
- copyRowToClipboard(row) {
3627
- const text = this.opts.visibleColDefs()
3628
- .map(col => getDisplayForField(col, row[col.field]))
3629
- .join('\t');
3798
+ /** Copies a row plus all marked rows as tab-separated text. */
3799
+ copyRowToClipboard(originalIndex) {
3800
+ const rows = this.opts.dataSource().rows();
3801
+ const cols = this.opts.visibleColDefs();
3802
+ const text = this.copyIndices(originalIndex)
3803
+ .map(index => cols
3804
+ .map(col => getDisplayForField(col, rows[index]?.[col.field], this.opts.locale()))
3805
+ .join('\t'))
3806
+ .join('\n');
3630
3807
  void this.browser.writeClipboard(text);
3631
3808
  this.closeCellContextMenu();
3632
3809
  }
3810
+ copyIndices(primaryIndex) {
3811
+ const length = this.opts.dataSource().length;
3812
+ const indices = [primaryIndex];
3813
+ for (const index of [...this.opts.markedRowIndices()].sort((a, b) => a - b)) {
3814
+ if (index !== primaryIndex && index >= 0 && index < length)
3815
+ indices.push(index);
3816
+ }
3817
+ return indices;
3818
+ }
3633
3819
  /** Inserts a row through the grid's central insertion callback. */
3634
3820
  insertRowAt(index) {
3635
3821
  this.opts.insertRowAt(index);
@@ -3748,13 +3934,15 @@ class AgridSidebarController {
3748
3934
  this.opts.dataSource().patchRow(index, { [field]: newValue });
3749
3935
  const colIndex = this.opts.visibleColDefs().findIndex(column => column.field === field);
3750
3936
  this.opts.control()?.pushEdit({ rowIndex: index, field, oldValue, newValue });
3937
+ const event = {
3938
+ position: { rowIndex: index, colIndex },
3939
+ field,
3940
+ oldValue,
3941
+ newValue,
3942
+ };
3943
+ this.opts.onFieldChange(event);
3751
3944
  if (!this.opts.useSidebarEditor()) {
3752
- this.opts.onCellEdit({
3753
- position: { rowIndex: index, colIndex },
3754
- field,
3755
- oldValue,
3756
- newValue,
3757
- });
3945
+ this.opts.onCellEdit(event);
3758
3946
  }
3759
3947
  }
3760
3948
  }
@@ -3835,7 +4023,9 @@ class AgridComponent {
3835
4023
  maxHeight = computed(() => this.provider().maxHeight, ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
3836
4024
  allowAddRows = computed(() => this.provider().allowAddRows, ...(ngDevMode ? [{ debugName: "allowAddRows" }] : /* istanbul ignore next */ []));
3837
4025
  autoAddRows = computed(() => this.provider().autoAddRows(), ...(ngDevMode ? [{ debugName: "autoAddRows" }] : /* istanbul ignore next */ []));
3838
- showControlColumn = computed(() => this.provider().showControlColumn, ...(ngDevMode ? [{ debugName: "showControlColumn" }] : /* istanbul ignore next */ []));
4026
+ enableRowMarking = computed(() => this.provider().enableRowMarking, ...(ngDevMode ? [{ debugName: "enableRowMarking" }] : /* istanbul ignore next */ []));
4027
+ showControlColumn = computed(() => this.provider().showControlColumn || this.enableRowMarking(), ...(ngDevMode ? [{ debugName: "showControlColumn" }] : /* istanbul ignore next */ []));
4028
+ controlColumnWidth = computed(() => this.enableRowMarking() ? 48 : 24, ...(ngDevMode ? [{ debugName: "controlColumnWidth" }] : /* istanbul ignore next */ []));
3839
4029
  showSidebar = computed(() => this.provider().showSidebar, ...(ngDevMode ? [{ debugName: "showSidebar" }] : /* istanbul ignore next */ []));
3840
4030
  autoOpenDetail = computed(() => this.provider().autoOpenDetail, ...(ngDevMode ? [{ debugName: "autoOpenDetail" }] : /* istanbul ignore next */ []));
3841
4031
  serverSideFiltering = computed(() => this.provider().serverSideFiltering, ...(ngDevMode ? [{ debugName: "serverSideFiltering" }] : /* istanbul ignore next */ []));
@@ -3845,7 +4035,10 @@ class AgridComponent {
3845
4035
  groupDescription = computed(() => this.provider().groupDescription, ...(ngDevMode ? [{ debugName: "groupDescription" }] : /* istanbul ignore next */ []));
3846
4036
  groupActions = computed(() => this.provider().groupActions, ...(ngDevMode ? [{ debugName: "groupActions" }] : /* istanbul ignore next */ []));
3847
4037
  cellMenuItems = computed(() => this.provider().cellMenuItems, ...(ngDevMode ? [{ debugName: "cellMenuItems" }] : /* istanbul ignore next */ []));
4038
+ headerGroups = computed(() => this.provider().headerGroups, ...(ngDevMode ? [{ debugName: "headerGroups" }] : /* istanbul ignore next */ []));
3848
4039
  zebraStripes = computed(() => this.provider().zebraStripes, ...(ngDevMode ? [{ debugName: "zebraStripes" }] : /* istanbul ignore next */ []));
4040
+ showChangedCellIndicator = computed(() => this.provider().showChangedCellIndicator, ...(ngDevMode ? [{ debugName: "showChangedCellIndicator" }] : /* istanbul ignore next */ []));
4041
+ confirmRowDelete = computed(() => this.provider().confirmRowDelete, ...(ngDevMode ? [{ debugName: "confirmRowDelete" }] : /* istanbul ignore next */ []));
3849
4042
  readonlyGrid = computed(() => this.provider().readonlyGrid(), ...(ngDevMode ? [{ debugName: "readonlyGrid" }] : /* istanbul ignore next */ []));
3850
4043
  loading = computed(() => this.provider().loading(), ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
3851
4044
  emptyText = computed(() => this.provider().emptyText, ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
@@ -3881,7 +4074,10 @@ class AgridComponent {
3881
4074
  rowDoubleClicked = output();
3882
4075
  /** Emitted when the user single-clicks a data row. */
3883
4076
  rowClick = output();
3884
- /** Emitted when the user has changed and saved a record via the sidebar editor save button */
4077
+ /**
4078
+ * Emitted once after a changed row is left during inline editing, or when the sidebar editor
4079
+ * save button is used.
4080
+ */
3885
4081
  rowChanged = output();
3886
4082
  /**
3887
4083
  * Emitted when the user navigates to a new page in **server-side pagination mode**
@@ -3896,6 +4092,15 @@ class AgridComponent {
3896
4092
  // ── Public state ─────────────────────────────────────────────────────────────
3897
4093
  /** Currently focused cell, or `null`. */
3898
4094
  selectedCell = signal(null, ...(ngDevMode ? [{ debugName: "selectedCell" }] : /* istanbul ignore next */ []));
4095
+ /** Original index of the row awaiting delete confirmation, or `null`. */
4096
+ pendingDeleteRow = signal(null, ...(ngDevMode ? [{ debugName: "pendingDeleteRow" }] : /* istanbul ignore next */ []));
4097
+ markedIndices = signal(new Set(), ...(ngDevMode ? [{ debugName: "markedIndices" }] : /* istanbul ignore next */ []));
4098
+ /** Original datasource indices marked for inclusion in copy operations. */
4099
+ markedRowIndices = this.markedIndices.asReadonly();
4100
+ /** Horizontal position of the delete prompt inside the scrollable row. */
4101
+ deleteConfirmationLeft = signal(0, ...(ngDevMode ? [{ debugName: "deleteConfirmationLeft" }] : /* istanbul ignore next */ []));
4102
+ /** Visible width available to the delete prompt. */
4103
+ deleteConfirmationWidth = signal(0, ...(ngDevMode ? [{ debugName: "deleteConfirmationWidth" }] : /* istanbul ignore next */ []));
3899
4104
  /** Rectangular cell range selected by Shift+arrow or Shift+click. */
3900
4105
  selectedRange = signal(null, ...(ngDevMode ? [{ debugName: "selectedRange" }] : /* istanbul ignore next */ []));
3901
4106
  /** Fill-handle drag preview bounds, in visible row/column coordinates. */
@@ -3924,9 +4129,7 @@ class AgridComponent {
3924
4129
  const originalIndex = this.sidebarController.selectedRowIndex();
3925
4130
  if (originalIndex === null)
3926
4131
  return;
3927
- const row = this.dataSource().getRow(originalIndex);
3928
- const saveEvent = { row, originalIndex };
3929
- this.rowChanged.emit(saveEvent);
4132
+ this.emitRowChanged(originalIndex);
3930
4133
  this.emitRecordEdit(originalIndex);
3931
4134
  this.sidebarController.closeSidebar();
3932
4135
  }
@@ -3950,6 +4153,31 @@ class AgridComponent {
3950
4153
  autosizeAllColumns() {
3951
4154
  this.columnSizing.autosizeAllColumns();
3952
4155
  }
4156
+ /**
4157
+ * Clears changed-cell markers after persistence succeeds.
4158
+ * Omit `originalIndex` to clear every marker; omit `fields` to clear the whole row.
4159
+ */
4160
+ clearChangedCells(originalIndex, fields) {
4161
+ if (originalIndex === undefined) {
4162
+ this.changedCells.set(new Set());
4163
+ return;
4164
+ }
4165
+ const fieldSet = fields ? new Set(fields) : null;
4166
+ this.changedCells.update(current => {
4167
+ const next = new Set(current);
4168
+ for (const key of current) {
4169
+ const marker = this.parseChangedCellKey(key);
4170
+ if (marker.rowIndex === originalIndex && (!fieldSet || fieldSet.has(marker.field))) {
4171
+ next.delete(key);
4172
+ }
4173
+ }
4174
+ return next;
4175
+ });
4176
+ }
4177
+ /** @internal Whether a cell has an unsaved-change marker. */
4178
+ isCellChanged(originalIndex, field) {
4179
+ return this.changedCells().has(this.changedCellKey(originalIndex, field));
4180
+ }
3953
4181
  /** @internal Full display value for a cell — used as the `title` tooltip attribute. */
3954
4182
  getCellTitle(col, value) {
3955
4183
  return this.presentation.getCellTitle(col, value);
@@ -3984,7 +4212,9 @@ class AgridComponent {
3984
4212
  columnLayout = new AgridColumnLayoutModel({
3985
4213
  control: this.control,
3986
4214
  colDefs: this.colDefs,
4215
+ headerGroups: this.headerGroups,
3987
4216
  showControlColumn: this.showControlColumn,
4217
+ controlColumnWidth: this.controlColumnWidth,
3988
4218
  getColumnWidth: col => this.getColumnWidth(col),
3989
4219
  getColumnWidthToken: col => this.getColumnWidthToken(col),
3990
4220
  });
@@ -4001,6 +4231,10 @@ class AgridComponent {
4001
4231
  hasRightPinnedPane = this.columnLayout.hasRightPinnedPane;
4002
4232
  hasPinnedPane = this.columnLayout.hasPinnedPane;
4003
4233
  hasFilterableColumns = this.columnLayout.hasFilterableColumns;
4234
+ hasHeaderGroups = this.columnLayout.hasHeaderGroups;
4235
+ pinnedHeaderGroupRuns = this.columnLayout.pinnedHeaderGroupRuns;
4236
+ scrollableHeaderGroupRuns = this.columnLayout.scrollableHeaderGroupRuns;
4237
+ rightHeaderGroupRuns = this.columnLayout.rightHeaderGroupRuns;
4004
4238
  columnState = new AgridColumnStateService({
4005
4239
  control: this.control,
4006
4240
  colDefs: this.colDefs,
@@ -4038,8 +4272,10 @@ class AgridComponent {
4038
4272
  /** Total number of pages given the current filter and page size. */
4039
4273
  totalPages = this.projection.totalPages;
4040
4274
  showPagination = this.projection.showPagination;
4041
- /** Number of rendered semantic rows, including the header row. */
4042
- ariaRowCount = computed(() => this.displayItems().length + 1 + (this.showFooter() ? 1 : 0), ...(ngDevMode ? [{ debugName: "ariaRowCount" }] : /* istanbul ignore next */ []));
4275
+ /** Number of semantic header rows currently rendered. */
4276
+ headerRowCount = computed(() => this.hasHeaderGroups() ? 2 : 1, ...(ngDevMode ? [{ debugName: "headerRowCount" }] : /* istanbul ignore next */ []));
4277
+ /** Number of rendered semantic rows, including header rows. */
4278
+ ariaRowCount = computed(() => this.displayItems().length + this.headerRowCount() + (this.showFooter() ? 1 : 0), ...(ngDevMode ? [{ debugName: "ariaRowCount" }] : /* istanbul ignore next */ []));
4043
4279
  /** Number of visible semantic columns, including the optional control column. */
4044
4280
  ariaColCount = computed(() => this.visibleColDefs().length + (this.showControlColumn() ? 1 : 0), ...(ngDevMode ? [{ debugName: "ariaColCount" }] : /* istanbul ignore next */ []));
4045
4281
  /** True when no rows or group headers are visible (ignores add-row sentinel and ghost). */
@@ -4206,14 +4442,23 @@ class AgridComponent {
4206
4442
  dataSource: this.dataSource,
4207
4443
  filteredItems: this.filteredItems,
4208
4444
  visibleColDefs: this.visibleColDefs,
4445
+ locale: this.locale,
4446
+ markedRowIndices: this.markedRowIndices,
4209
4447
  rowSelection: this.rowSelection,
4210
4448
  selectedCell: this.selectedCell,
4211
4449
  editingCell: this.editController.editingCell,
4212
- insertRowAt: index => this.navigationController.insertRowAt(index),
4450
+ insertRowAt: index => {
4451
+ this.reconcileMarkedRowsAfterInsertion(index);
4452
+ this.navigationController.insertRowAt(index);
4453
+ },
4213
4454
  startDragSelect: originalIndex => this.dragHandler.startDragSelect(originalIndex),
4214
4455
  onRowSelect: event => this.rowSelect.emit(event),
4215
4456
  onRowClick: event => this.rowClick.emit(event),
4216
- onRowRemoved: event => this.rowRemoved.emit(this.createRecordEvent(event.index, event.data)),
4457
+ onRowRemoved: event => {
4458
+ this.reconcileDirtyInlineRowsAfterRemoval(event.index);
4459
+ this.reconcileMarkedRowsAfterRemoval(event.index);
4460
+ this.rowRemoved.emit(this.createRecordEvent(event.index, event.data));
4461
+ },
4217
4462
  onEditRowRemoved: originalIndex => this.editController.onRowRemoved(originalIndex),
4218
4463
  closeFilterMenu: () => this.columnMenuController.close(),
4219
4464
  closeGroupActionsMenu: () => this.closeGroupActionsMenu(),
@@ -4230,7 +4475,8 @@ class AgridComponent {
4230
4475
  selectedRowIndex: this.selectedRowIndex,
4231
4476
  autoOpenDetail: this.autoOpenDetail,
4232
4477
  useSidebarEditor: this.useSidebarEditor,
4233
- onCellEdit: event => this.emitEditEvents(event),
4478
+ onFieldChange: event => this.markCellChanged(event),
4479
+ onCellEdit: event => this.emitSidebarEditEvents(event),
4234
4480
  });
4235
4481
  sidebarOpen = this.sidebarController.open;
4236
4482
  sidebarTab = this.sidebarController.tab;
@@ -4244,6 +4490,7 @@ class AgridComponent {
4244
4490
  locale: this.locale,
4245
4491
  selectedCell: this.selectedCell,
4246
4492
  selectedRange: this.selectedRange,
4493
+ markedRowIndices: this.markedRowIndices,
4247
4494
  isCellEditable: col => this.isCellEditable(col),
4248
4495
  onCellEdit: event => this.emitEditEvents(event),
4249
4496
  scrollToCell: (displayIndex, colIndex) => this.scrollToKeepVisible(displayIndex, colIndex),
@@ -4253,7 +4500,10 @@ class AgridComponent {
4253
4500
  filteredItems: () => this.filteredItems(),
4254
4501
  locale: () => this.locale(),
4255
4502
  selectedIndices: this.rowController.selectedIndices,
4256
- onReorder: e => this.rowReorder.emit(e),
4503
+ onReorder: e => {
4504
+ this.reconcileMarkedRowsAfterMove(e.oldIndex, e.newIndex);
4505
+ this.rowReorder.emit(e);
4506
+ },
4257
4507
  onSelectionChange: () => this.rowController.emitSelection(),
4258
4508
  }, this.destroyRef);
4259
4509
  columnReorder = new AgridColumnReorderController({
@@ -4261,10 +4511,23 @@ class AgridComponent {
4261
4511
  visibleColDefs: this.visibleColDefs,
4262
4512
  getColDef: field => this.getColDef(field),
4263
4513
  }, this.destroyRef);
4514
+ columnDragPreview = this.columnReorder.preview;
4264
4515
  /** @internal Start a column header drag. */
4265
4516
  onColHeaderPointerDown(event, field) {
4266
4517
  this.columnReorder.start(event, field);
4267
4518
  }
4519
+ /** @internal Start dragging all columns in one contiguous grouped-header segment. */
4520
+ onHeaderGroupPointerDown(event, fields, label) {
4521
+ this.columnReorder.startGroup(event, fields, label);
4522
+ }
4523
+ /** @internal Whether any field in a grouped-header segment is being dragged. */
4524
+ isHeaderGroupDragging(fields) {
4525
+ return fields.some(field => this.columnReorder.isDragging(field));
4526
+ }
4527
+ /** @internal Whether a grouped-header segment contains a locked column. */
4528
+ isHeaderGroupLocked(fields) {
4529
+ return fields.some(field => this.getColDef(field)?.locked);
4530
+ }
4268
4531
  /** @internal Whether the given column header is being dragged. */
4269
4532
  isColDragging(field) {
4270
4533
  return this.columnReorder.isDragging(field);
@@ -4273,17 +4536,106 @@ class AgridComponent {
4273
4536
  getColDropSide(field) {
4274
4537
  return this.columnReorder.getDropSide(field);
4275
4538
  }
4539
+ /** @internal Horizontal animation offset for a header during column reordering. */
4540
+ getColReorderOffset(field) {
4541
+ return this.columnReorder.getHeaderOffset(field);
4542
+ }
4276
4543
  // ── Setup ─────────────────────────────────────────────────────────────────────
4277
4544
  _seededControls = new WeakSet();
4545
+ dirtyInlineRows = new Set();
4546
+ dirtyRowsDataSource = null;
4547
+ changedCells = signal(new Set(), ...(ngDevMode ? [{ debugName: "changedCells" }] : /* istanbul ignore next */ []));
4548
+ changedCellsDataSource = null;
4278
4549
  emitEditEvents(event) {
4279
4550
  this.cellEdit.emit(event);
4280
4551
  this.emitRecordEdit(event.position.rowIndex);
4552
+ this.markInlineRowDirty(event.position.rowIndex);
4553
+ this.markCellChanged(event);
4554
+ }
4555
+ emitSidebarEditEvents(event) {
4556
+ this.cellEdit.emit(event);
4557
+ this.emitRecordEdit(event.position.rowIndex);
4281
4558
  }
4282
4559
  emitRecordEdit(index) {
4283
4560
  const datasource = this.dataSource();
4284
4561
  const event = this.createRecordEvent(index, datasource.getRow(index));
4285
4562
  queueMicrotask(() => this.recordEdit.emit(event));
4286
4563
  }
4564
+ markInlineRowDirty(index) {
4565
+ const datasource = this.dataSource();
4566
+ if (this.dirtyRowsDataSource !== datasource) {
4567
+ this.dirtyInlineRows.clear();
4568
+ this.dirtyRowsDataSource = datasource;
4569
+ }
4570
+ this.dirtyInlineRows.add(index);
4571
+ }
4572
+ markCellChanged(event) {
4573
+ if (!this.showChangedCellIndicator())
4574
+ return;
4575
+ const datasource = this.dataSource();
4576
+ if (this.changedCellsDataSource !== datasource) {
4577
+ this.changedCells.set(new Set());
4578
+ this.changedCellsDataSource = datasource;
4579
+ }
4580
+ this.changedCells.update(current => {
4581
+ const next = new Set(current);
4582
+ next.add(this.changedCellKey(event.position.rowIndex, event.field));
4583
+ return next;
4584
+ });
4585
+ }
4586
+ changedCellKey(rowIndex, field) {
4587
+ return JSON.stringify([rowIndex, field]);
4588
+ }
4589
+ parseChangedCellKey(key) {
4590
+ const [rowIndex, field] = JSON.parse(key);
4591
+ return { rowIndex, field };
4592
+ }
4593
+ flushDirtyInlineRows(activeRowIndex = null) {
4594
+ const datasource = this.dataSource();
4595
+ if (this.dirtyRowsDataSource !== datasource) {
4596
+ this.dirtyInlineRows.clear();
4597
+ this.dirtyRowsDataSource = datasource;
4598
+ return;
4599
+ }
4600
+ for (const index of [...this.dirtyInlineRows].sort((a, b) => a - b)) {
4601
+ if (index === activeRowIndex)
4602
+ continue;
4603
+ this.dirtyInlineRows.delete(index);
4604
+ if (index >= 0 && index < datasource.length)
4605
+ this.emitRowChanged(index);
4606
+ }
4607
+ }
4608
+ reconcileDirtyInlineRowsAfterRemoval(removedIndex) {
4609
+ const shifted = new Set();
4610
+ for (const index of this.dirtyInlineRows) {
4611
+ if (index < removedIndex)
4612
+ shifted.add(index);
4613
+ else if (index > removedIndex)
4614
+ shifted.add(index - 1);
4615
+ }
4616
+ this.dirtyInlineRows.clear();
4617
+ for (const index of shifted)
4618
+ this.dirtyInlineRows.add(index);
4619
+ this.reconcileChangedCellsAfterRemoval(removedIndex);
4620
+ }
4621
+ reconcileChangedCellsAfterRemoval(removedIndex) {
4622
+ const shifted = new Set();
4623
+ for (const key of this.changedCells()) {
4624
+ const marker = this.parseChangedCellKey(key);
4625
+ if (marker.rowIndex < removedIndex)
4626
+ shifted.add(key);
4627
+ else if (marker.rowIndex > removedIndex) {
4628
+ shifted.add(this.changedCellKey(marker.rowIndex - 1, marker.field));
4629
+ }
4630
+ }
4631
+ this.changedCells.set(shifted);
4632
+ }
4633
+ emitRowChanged(originalIndex) {
4634
+ this.rowChanged.emit({
4635
+ row: this.dataSource().getRow(originalIndex),
4636
+ originalIndex,
4637
+ });
4638
+ }
4287
4639
  createRecordEvent(index, data) {
4288
4640
  const datasource = this.dataSource();
4289
4641
  return {
@@ -4295,6 +4647,17 @@ class AgridComponent {
4295
4647
  }
4296
4648
  constructor() {
4297
4649
  effect(() => this.sidebarController.syncAutoOpen());
4650
+ effect(() => {
4651
+ const datasource = this.dataSource();
4652
+ if (this.changedCellsDataSource === datasource)
4653
+ return;
4654
+ this.changedCellsDataSource = datasource;
4655
+ this.changedCells.set(new Set());
4656
+ });
4657
+ effect(() => {
4658
+ const activeRowIndex = this.selectedCell()?.rowIndex ?? null;
4659
+ this.flushDirtyInlineRows(activeRowIndex);
4660
+ });
4298
4661
  afterNextRender(() => {
4299
4662
  const wrapper = this.wrapperEl().nativeElement;
4300
4663
  const onKeyDown = (event) => this.onKeyDown(event);
@@ -4321,6 +4684,9 @@ class AgridComponent {
4321
4684
  });
4322
4685
  // Deselect when clicking outside the grid.
4323
4686
  const onOutsidePointerDown = (e) => {
4687
+ if (!this._hostEl.nativeElement.contains(e.target)) {
4688
+ queueMicrotask(() => this.flushDirtyInlineRows());
4689
+ }
4324
4690
  if (this.rowSelection() === 'none')
4325
4691
  return;
4326
4692
  if (this.selectedRowIndices().size === 0)
@@ -4511,8 +4877,20 @@ class AgridComponent {
4511
4877
  }
4512
4878
  /** @internal Main keyboard handler delegated from the wrapper div. */
4513
4879
  onKeyDown(event) {
4880
+ if (event.key === 'Escape' && this.pendingDeleteRow() !== null) {
4881
+ event.preventDefault();
4882
+ event.stopPropagation();
4883
+ this.cancelRowDelete();
4884
+ return;
4885
+ }
4514
4886
  this.navigationController.handleKeyDown(event);
4515
4887
  }
4888
+ /** @internal Clears cell navigation while a header filter control owns focus. */
4889
+ onGridFocusIn(event) {
4890
+ if (event.target?.closest('.ag-filter-input, .ag-filter-menu')) {
4891
+ this.navigationController.deactivateCell();
4892
+ }
4893
+ }
4516
4894
  /** Open the find panel and focus its input. */
4517
4895
  openFind() {
4518
4896
  this.findController.show();
@@ -4547,6 +4925,25 @@ class AgridComponent {
4547
4925
  }
4548
4926
  this.rowController.selectFromPointer(event, originalIndex, false);
4549
4927
  }
4928
+ /** @internal Toggle whether a row is included in subsequent copy operations. */
4929
+ toggleRowMarked(originalIndex) {
4930
+ this.markedIndices.update(indices => {
4931
+ const next = new Set(indices);
4932
+ if (next.has(originalIndex))
4933
+ next.delete(originalIndex);
4934
+ else
4935
+ next.add(originalIndex);
4936
+ return next;
4937
+ });
4938
+ }
4939
+ /** @internal Returns whether a row is marked for copying. */
4940
+ isRowMarked(originalIndex) {
4941
+ return this.markedIndices().has(originalIndex);
4942
+ }
4943
+ /** Clear every row marked for clipboard inclusion. */
4944
+ clearMarkedRows() {
4945
+ this.markedIndices.set(new Set());
4946
+ }
4550
4947
  /** @internal Copy the active range or cell as TSV. */
4551
4948
  onCopy(event) {
4552
4949
  this.clipboardHandler.copy(event);
@@ -4600,21 +4997,59 @@ class AgridComponent {
4600
4997
  });
4601
4998
  this.closeCellContextMenu();
4602
4999
  }
4603
- /** @internal Copy the display value of one cell to the clipboard. */
4604
- copyCellToClipboard(value, col) {
4605
- this.rowController.copyCellToClipboard(value, col);
5000
+ /** @internal Copy one field from the target and marked rows. */
5001
+ copyCellToClipboard(originalIndex, col) {
5002
+ this.rowController.copyCellToClipboard(originalIndex, col);
4606
5003
  }
4607
- /** @internal Copy all visible column values of a row as TSV to the clipboard. */
4608
- copyRowToClipboard(row) {
4609
- this.rowController.copyRowToClipboard(row);
5004
+ /** @internal Copy the target and marked rows using all visible fields. */
5005
+ copyRowToClipboard(originalIndex) {
5006
+ this.rowController.copyRowToClipboard(originalIndex);
4610
5007
  }
4611
5008
  /** @internal Insert a blank row at a specific position and emit prepareAddRecord. */
4612
5009
  insertRowAt(atIndex) {
4613
5010
  this.rowController.insertRowAt(atIndex);
4614
5011
  }
4615
- /** Delete the row at `originalIndex`, adjusting stale cell/edit pointers. */
5012
+ /** Start confirmation or immediately delete the row at `originalIndex`. */
4616
5013
  deleteRow(originalIndex) {
5014
+ if (this.confirmRowDelete()) {
5015
+ this.updateDeleteConfirmationPosition();
5016
+ this.pendingDeleteRow.set(originalIndex);
5017
+ this.rowController.closeContextMenu();
5018
+ this.rowController.closeCellContextMenu();
5019
+ this.browser.schedule(() => {
5020
+ this._hostEl.nativeElement
5021
+ .querySelector('[data-delete-confirm-no]')
5022
+ ?.focus();
5023
+ });
5024
+ return;
5025
+ }
5026
+ this.deleteRowImmediately(originalIndex);
5027
+ }
5028
+ /** @internal Returns whether this row is awaiting delete confirmation. */
5029
+ isRowPendingDelete(originalIndex) {
5030
+ return this.pendingDeleteRow() === originalIndex;
5031
+ }
5032
+ /** @internal Delete the row currently awaiting confirmation. */
5033
+ confirmPendingRowDelete() {
5034
+ const originalIndex = this.pendingDeleteRow();
5035
+ if (originalIndex === null)
5036
+ return;
5037
+ this.pendingDeleteRow.set(null);
5038
+ this.deleteRowImmediately(originalIndex);
5039
+ }
5040
+ /** @internal Cancel the active row-delete confirmation. */
5041
+ cancelRowDelete() {
5042
+ this.pendingDeleteRow.set(null);
5043
+ this.wrapperEl().nativeElement.focus();
5044
+ }
5045
+ deleteRowImmediately(originalIndex) {
4617
5046
  this.rowController.deleteRow(originalIndex);
5047
+ this.rowController.closeCellContextMenu();
5048
+ }
5049
+ updateDeleteConfirmationPosition() {
5050
+ const scroller = this.horizontalScrollerEl().nativeElement;
5051
+ this.deleteConfirmationLeft.set(scroller.scrollLeft);
5052
+ this.deleteConfirmationWidth.set(scroller.clientWidth);
4618
5053
  }
4619
5054
  // ── Group expand / collapse ───────────────────────────────────────────────────
4620
5055
  /** @internal */
@@ -4696,6 +5131,10 @@ class AgridComponent {
4696
5131
  this.pinnedViewport()?.scrollToOffset(offset);
4697
5132
  this.rightPinnedViewport()?.scrollToOffset(offset);
4698
5133
  }
5134
+ /** @internal Keeps the row-delete prompt visible while columns scroll horizontally. */
5135
+ onHorizontalScroll() {
5136
+ this.updateDeleteConfirmationPosition();
5137
+ }
4699
5138
  /** @internal */
4700
5139
  onRightPinnedBodyScroll() {
4701
5140
  const right = this.rightPinnedViewport();
@@ -4731,6 +5170,32 @@ class AgridComponent {
4731
5170
  findDisplayIndex(originalIndex) {
4732
5171
  return this.navigationController.findDisplayIndex(originalIndex);
4733
5172
  }
5173
+ reconcileMarkedRowsAfterInsertion(insertedIndex) {
5174
+ if (this.markedIndices().size === 0)
5175
+ return;
5176
+ this.markedIndices.update(indices => new Set([...indices].map(index => index >= insertedIndex ? index + 1 : index)));
5177
+ }
5178
+ reconcileMarkedRowsAfterRemoval(removedIndex) {
5179
+ if (this.markedIndices().size === 0)
5180
+ return;
5181
+ this.markedIndices.update(indices => new Set([...indices]
5182
+ .filter(index => index !== removedIndex)
5183
+ .map(index => index > removedIndex ? index - 1 : index)));
5184
+ }
5185
+ reconcileMarkedRowsAfterMove(oldIndex, newIndex) {
5186
+ if (this.markedIndices().size === 0 || oldIndex === newIndex)
5187
+ return;
5188
+ const destination = newIndex > oldIndex ? newIndex - 1 : newIndex;
5189
+ this.markedIndices.update(indices => new Set([...indices].map(index => {
5190
+ if (index === oldIndex)
5191
+ return destination;
5192
+ if (oldIndex < destination && index > oldIndex && index <= destination)
5193
+ return index - 1;
5194
+ if (destination < oldIndex && index >= destination && index < oldIndex)
5195
+ return index + 1;
5196
+ return index;
5197
+ })));
5198
+ }
4734
5199
  isCellEditable(col) {
4735
5200
  return this.editController.isCellEditable(col);
4736
5201
  }
@@ -4771,7 +5236,7 @@ class AgridComponent {
4771
5236
  return this.columnSizing.getWidthToken(col);
4772
5237
  }
4773
5238
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AgridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4774
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", 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", rowDoubleClicked: "rowDoubleClicked", rowClick: "rowClick", rowChanged: "rowChanged", pageChange: "pageChange", filterChange: "filterChange", sortChange: "sortChange" }, 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 }], 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\"\n [attr.aria-busy]=\"loading() ? 'true' : null\" (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu()\">\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 <div class=\"ag-header ag-header--pinned\" role=\"row\" aria-rowindex=\"1\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\" [style.width.px]=\"pinnedPaneWidth()\">\n @if (showControlColumn()) {\n <div class=\"ag-header-cell ag-control-header\" role=\"columnheader\" aria-colindex=\"1\">\n <div class=\"ag-header-cell-top\"></div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\"></div>\n }\n </div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [class.ag-header-cell--pinned-last]=\"isLastPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [itemSize]=\"rowHeight()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + 2\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isPinnedPaneRowSelected(item)\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\" (click)=\"$event.stopPropagation()\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\"></div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\" [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">{{\n getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + 2\"\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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">\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\">\n <div class=\"ag-header\" role=\"row\" aria-rowindex=\"1\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-header-cell\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [attr.data-col-field]=\"col.field\" (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">\u229F</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [itemSize]=\"rowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + 2\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 @for (col of scrollableColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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--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 (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-ghost-cell\">{{ getGhostCellDisplay(col) }}</div>\n }\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 </div>\n </div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + 2\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\">\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 <div class=\"ag-header\" role=\"row\" aria-rowindex=\"1\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\" [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">'\u229F '</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [itemSize]=\"rowHeight()\" [style.width.px]=\"rightPinnedPaneWidth()\" (scroll)=\"onRightPinnedBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + 2\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (col of rightPinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\n [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--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]=\"isFirstRightPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">{{ getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + 2\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">\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\n [open]=\"sidebarOpen()\"\n [activeTab]=\"sidebarTab()\"\n [columns]=\"colDefs()\"\n [row]=\"sidebarRow()\"\n [hiddenColumns]=\"sidebarHiddenColumns()\"\n [locale]=\"locale()\"\n [localeText]=\"localeText()\"\n [readonlyGrid]=\"readonlyGrid()\"\n [useSidebarEditor]=\"useSidebarEditor()\"\n (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\"\n (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\"\n />\n }\n </div><!-- /.ag-main-area -->\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\"\n [disabled]=\"control()!.currentPage() <= 1\" (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\"\n [disabled]=\"control()!.currentPage() <= 1\" (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\"\n (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\"\n (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 <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 ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n </div>\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.value, col)\">{{ localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.row)\">{{ localeText().copyRow }}</button>\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 }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{ 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\"\n (click)=\"deleteRow(menu.rowIndex); closeCellContextMenu()\">{{ 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\" [disabled]=\"item.disabled\"\n (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]=\"sortOption() !== 'none'\"\n [showColumnActions]=\"!!control()\" [pinned]=\"getColumnPinState(menu.field)\"\n [groupable]=\"!!getColDef(menu.field)?.groupable\" [grouped]=\"isGroupedByField(menu.field)\"\n [filterable]=\"!!getColDef(menu.field)?.filterable\" [showValueFilter]=\"!serverSideFiltering()\"\n [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\"\n [valueItems]=\"serverSideFiltering() || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\"\n [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 (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\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}}: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-header{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-bottom:2px solid var(--agrid-color-border)}.ag-header-cell{position:relative;display:flex;align-items:center;font-weight:600;border-right:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;-webkit-user-select:none;user-select:none;box-sizing:border-box}.ag-header-cell:last-child{border-right:none}.ag-header-cell-top{display:flex;align-items:center;flex:1;min-width:0;padding:0 6px;height:32px;overflow:hidden;white-space:nowrap}.ag-header-cell-label{overflow:hidden;text-overflow:ellipsis;flex:1}.ag-header--with-filters .ag-header-cell{flex-direction:column;align-items:stretch;height:auto;white-space:normal}.ag-header--with-filters .ag-header-cell-top{flex:0 0 32px}.ag-header-cell-filter{height:28px;display:flex;align-items:center;padding:0 2px;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-header-cell{cursor:grab}.ag-header-cell--dragging{opacity:.45;cursor:grabbing}.ag-header-cell--drop-before{box-shadow:inset 2px 0 0 var(--agrid-color-accent)}.ag-header-cell--drop-after{box-shadow:inset -2px 0 0 var(--agrid-color-accent)}.ag-sort-badge{font-size:11px;color:var(--agrid-color-accent);flex-shrink:0;line-height:1}.ag-sort-priority{font-size:9px;vertical-align:super;opacity:.75}.ag-resize-handle{position:absolute;top:0;right:0;width:5px;height:100%;cursor:col-resize;z-index:1}.ag-resize-handle:hover{background:var(--agrid-color-accent);opacity:.5}.ag-filter-input{flex:1;min-width:0;height:20px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 4px;background:var(--agrid-color-bg)}.ag-filter-input:focus{border-color:var(--agrid-color-accent)}.ag-header-cell--filtered .ag-header-cell-label:after{content:\" \\25be\";font-size:9px;color:var(--agrid-color-accent)}.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}: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 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-header{z-index:3;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted)}.ag-control-header .ag-header-cell-filter{background:var(--agrid-color-bg-subtle)}.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;box-sizing:border-box}.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--reorder:after{content:\"\\283f\";font-size:13px;color:var(--agrid-color-border)}.ag-control-cell--reorder:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder:active{cursor:grabbing}.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-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-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-header-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-header-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-header-cell--pinned-first{box-shadow:none}.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-header-menu-btn{flex-shrink:0;width:16px;height:16px;padding:0;margin-right:2px;background:none;border:1px solid transparent;border-radius:3px;cursor:pointer;font-size:10px;color:var(--agrid-color-text-muted);display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity .12s;line-height:1}.ag-header-menu-btn--active{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle)}.ag-header-menu-btn:hover{background:var(--agrid-color-bg);border-color:var(--agrid-color-border)}\n"], dependencies: [{ kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { 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: "component", type: AgridCellComponent, selector: "agrid-cell", inputs: ["col", "rowIndex", "colIndex", "value", "row", "locale", "selected", "editing", "seedChar"], outputs: ["activate", "startEdit", "draftChange"] }, { kind: "component", type: AgridColumnMenuComponent, selector: "agrid-column-menu", inputs: ["localeText", "x", "y", "header", "sortDir", "sortable", "showColumnActions", "pinned", "groupable", "grouped", "filterable", "showValueFilter", "search", "allSelected", "valueItems", "sortPriority", "hasMultiSort", "aggregate"], outputs: ["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", "row", "hiddenColumns", "locale", "localeText", "readonlyGrid", "useSidebarEditor"], outputs: ["close", "tabChange", "toggleColumn", "detailEdit", "save"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5239
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", 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", rowDoubleClicked: "rowDoubleClicked", rowClick: "rowClick", rowChanged: "rowChanged", pageChange: "pageChange", filterChange: "filterChange", sortChange: "sortChange" }, 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 }], 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\"\n [attr.aria-busy]=\"loading() ? 'true' : null\" (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\"\n (focusin)=\"onGridFocusIn($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu()\">\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 @if (hasHeaderGroups()) {\n <div class=\"ag-header-groups ag-header-groups--pinned\" role=\"row\" aria-rowindex=\"1\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\" [style.width.px]=\"pinnedPaneWidth()\">\n @if (showControlColumn()) {\n <div class=\"ag-header-group-cell ag-header-group-cell--empty\"></div>\n }\n @for (run of pinnedHeaderGroupRuns(); track run.key) {\n <div class=\"ag-header-group-cell\" role=\"columnheader\"\n [attr.data-header-group]=\"run.id\"\n [class.ag-header-group-cell--empty]=\"!run.id\"\n [class.ag-header-group-cell--locked]=\"isHeaderGroupLocked(run.fields)\"\n [class.ag-header-group-cell--dragging]=\"isHeaderGroupDragging(run.fields)\"\n [style.grid-column]=\"'span ' + run.span\"\n (pointerdown)=\"run.id && onHeaderGroupPointerDown($event, run.fields, run.label)\">\n {{ run.label }}\n </div>\n }\n </div>\n }\n <div class=\"ag-header ag-header--pinned\" role=\"row\" [attr.aria-rowindex]=\"headerRowCount()\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\" [style.width.px]=\"pinnedPaneWidth()\">\n @if (showControlColumn()) {\n <div class=\"ag-header-cell ag-control-header\" role=\"columnheader\" aria-colindex=\"1\">\n <div class=\"ag-header-cell-top\"></div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\"></div>\n }\n </div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-header-cell--pinned-last]=\"isLastPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [itemSize]=\"rowHeight()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + headerRowCount() + 1\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\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 [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\" (click)=\"$event.stopPropagation()\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\">\n @if (enableRowMarking()) {\n <input class=\"ag-row-marker\" type=\"checkbox\" [checked]=\"isRowMarked(item.originalIndex)\"\n [attr.aria-label]=\"localeText().markRow\"\n (pointerdown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRowMarked(item.originalIndex)\" />\n }\n </div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">{{\n getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\"\n [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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">\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 @if (hasHeaderGroups()) {\n <div class=\"ag-header-groups\" role=\"row\" aria-rowindex=\"1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (run of scrollableHeaderGroupRuns(); track run.key) {\n <div class=\"ag-header-group-cell\" role=\"columnheader\"\n [attr.data-header-group]=\"run.id\"\n [class.ag-header-group-cell--empty]=\"!run.id\"\n [class.ag-header-group-cell--locked]=\"isHeaderGroupLocked(run.fields)\"\n [class.ag-header-group-cell--dragging]=\"isHeaderGroupDragging(run.fields)\"\n [style.grid-column]=\"'span ' + run.span\"\n (pointerdown)=\"run.id && onHeaderGroupPointerDown($event, run.fields, run.label)\">\n {{ run.label }}\n </div>\n }\n </div>\n }\n <div class=\"ag-header\" role=\"row\" [attr.aria-rowindex]=\"headerRowCount()\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-header-cell\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.data-col-field]=\"col.field\" (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">\u229F</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [itemSize]=\"rowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + headerRowCount() + 1\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\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 [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 @for (col of scrollableColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + '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 (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-ghost-cell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\">{{\n getGhostCellDisplay(col) }}</div>\n }\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 </div>\n </div>\n }\n @if (isDataRowItem(item) && isRowPendingDelete(item.originalIndex)) {\n <div class=\"ag-delete-confirmation\" role=\"alertdialog\"\n [attr.aria-label]=\"localeText().confirmDeleteRow\"\n [style.left.px]=\"deleteConfirmationLeft()\"\n [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\"\n type=\"button\" (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 </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\"\n [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\">\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 @if (hasHeaderGroups()) {\n <div class=\"ag-header-groups\" role=\"row\" aria-rowindex=\"1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\" [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (run of rightHeaderGroupRuns(); track run.key) {\n <div class=\"ag-header-group-cell\" role=\"columnheader\"\n [attr.data-header-group]=\"run.id\"\n [class.ag-header-group-cell--empty]=\"!run.id\"\n [class.ag-header-group-cell--locked]=\"isHeaderGroupLocked(run.fields)\"\n [class.ag-header-group-cell--dragging]=\"isHeaderGroupDragging(run.fields)\"\n [style.grid-column]=\"'span ' + run.span\"\n (pointerdown)=\"run.id && onHeaderGroupPointerDown($event, run.fields, run.label)\">\n {{ run.label }}\n </div>\n }\n </div>\n }\n <div class=\"ag-header\" role=\"row\" [attr.aria-rowindex]=\"headerRowCount()\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\" [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-header-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">'\u229F '</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [itemSize]=\"rowHeight()\" [style.width.px]=\"rightPinnedPaneWidth()\" (scroll)=\"onRightPinnedBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + headerRowCount() + 1\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(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 [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (col of rightPinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\n [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-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + '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]=\"isFirstRightPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">{{ getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\"\n [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">\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\n [open]=\"sidebarOpen()\"\n [activeTab]=\"sidebarTab()\"\n [columns]=\"colDefs()\"\n [row]=\"sidebarRow()\"\n [hiddenColumns]=\"sidebarHiddenColumns()\"\n [locale]=\"locale()\"\n [localeText]=\"localeText()\"\n [readonlyGrid]=\"readonlyGrid()\"\n [useSidebarEditor]=\"useSidebarEditor()\"\n (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\"\n (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\"\n />\n }\n </div><!-- /.ag-main-area -->\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\"\n [disabled]=\"control()!.currentPage() <= 1\" (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\"\n [disabled]=\"control()!.currentPage() <= 1\" (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\"\n (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\"\n (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 <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 ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n </div>\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)\">{{ localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.rowIndex)\">{{ localeText().copyRow }}</button>\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 }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{ 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\"\n (click)=\"deleteRow(menu.rowIndex)\">{{ 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\" [disabled]=\"item.disabled\"\n (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]=\"sortOption() !== 'none'\"\n [showColumnActions]=\"!!control()\" [pinned]=\"getColumnPinState(menu.field)\"\n [groupable]=\"!!getColDef(menu.field)?.groupable\" [grouped]=\"isGroupedByField(menu.field)\"\n [filterable]=\"!!getColDef(menu.field)?.filterable\" [showValueFilter]=\"!serverSideFiltering()\"\n [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\"\n [valueItems]=\"serverSideFiltering() || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\"\n [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 (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\n }\n\n @if (columnDragPreview(); as preview) {\n <div class=\"ag-column-drag-preview\"\n [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}}: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-header{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-bottom:2px solid var(--agrid-color-border)}.ag-header-groups{display:grid;flex-shrink:0;height:28px;background:color-mix(in srgb,var(--agrid-color-bg-muted) 72%,var(--agrid-color-bg));border-bottom:1px solid var(--agrid-color-border)}.ag-header-group-cell{display:flex;align-items:center;justify-content:center;min-width:0;padding:0 8px;overflow:hidden;border-right:1px solid var(--agrid-color-border);box-sizing:border-box;color:var(--agrid-color-text);font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap;cursor:grab;-webkit-user-select:none;user-select:none;transition:opacity .1s ease}.ag-header-group-cell:last-child{border-right:none}.ag-header-group-cell--empty,.ag-header-group-cell--locked{cursor:default}.ag-header-group-cell--dragging{opacity:.12}.ag-header-cell{position:relative;display:flex;align-items:center;font-weight:600;border-right:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;-webkit-user-select:none;user-select:none;box-sizing:border-box}.ag-header-cell:last-child{border-right:none}.ag-header-cell-top{display:flex;align-items:center;flex:1;min-width:0;padding:0 6px;height:32px;overflow:hidden;white-space:nowrap}.ag-header-cell-label{overflow:hidden;text-overflow:ellipsis;flex:1}.ag-header--with-filters .ag-header-cell{flex-direction:column;align-items:stretch;height:auto;white-space:normal}.ag-header--with-filters .ag-header-cell-top{flex:0 0 32px}.ag-header-cell-filter{height:28px;display:flex;align-items:center;padding:0 2px;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-header-cell{cursor:grab;transition:transform .16s cubic-bezier(.2,0,0,1),opacity .1s ease;will-change:transform}.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-header-cell--dragging{opacity:.12;cursor:grabbing}.ag-column-reorder-item--dragging{opacity:.12}.ag-header-cell--drop-before,.ag-header-cell--drop-after{z-index:1}.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-sort-badge{font-size:11px;color:var(--agrid-color-accent);flex-shrink:0;line-height:1}.ag-sort-priority{font-size:9px;vertical-align:super;opacity:.75}.ag-resize-handle{position:absolute;top:0;right:0;width:5px;height:100%;cursor:col-resize;z-index:1}.ag-resize-handle:hover{background:var(--agrid-color-accent);opacity:.5}.ag-filter-input{flex:1;min-width:0;height:20px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 4px;background:var(--agrid-color-bg)}.ag-filter-input:focus{border-color:var(--agrid-color-accent)}.ag-header-cell--filtered .ag-header-cell-label:after{content:\" \\25be\";font-size:9px;color:var(--agrid-color-accent)}.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}.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--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-header{z-index:3;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted)}.ag-control-header .ag-header-cell-filter{background:var(--agrid-color-bg-subtle)}.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--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-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-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-header-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-header-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-header-cell--pinned-first{box-shadow:none}.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-header-menu-btn{flex-shrink:0;width:16px;height:16px;padding:0;margin-right:2px;background:none;border:1px solid transparent;border-radius:3px;cursor:pointer;font-size:10px;color:var(--agrid-color-text-muted);display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity .12s;line-height:1}.ag-header-menu-btn--active{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle)}.ag-header-menu-btn:hover{background:var(--agrid-color-bg);border-color:var(--agrid-color-border)}\n"], dependencies: [{ kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { 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: "component", type: AgridCellComponent, selector: "agrid-cell", inputs: ["col", "rowIndex", "colIndex", "value", "row", "locale", "selected", "editing", "seedChar"], outputs: ["activate", "startEdit", "draftChange"] }, { kind: "component", type: AgridColumnMenuComponent, selector: "agrid-column-menu", inputs: ["localeText", "x", "y", "header", "sortDir", "sortable", "showColumnActions", "pinned", "groupable", "grouped", "filterable", "showValueFilter", "search", "allSelected", "valueItems", "sortPriority", "hasMultiSort", "aggregate"], outputs: ["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", "row", "hiddenColumns", "locale", "localeText", "readonlyGrid", "useSidebarEditor"], outputs: ["close", "tabChange", "toggleColumn", "detailEdit", "save"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4775
5240
  }
4776
5241
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AgridComponent, decorators: [{
4777
5242
  type: Component,
@@ -4785,7 +5250,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
4785
5250
  '[class.ag-zebra]': 'zebraStripes()',
4786
5251
  '[style.min-height]': 'minHeight()',
4787
5252
  '[style.max-height]': 'maxHeight()',
4788
- }, 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\"\n [attr.aria-busy]=\"loading() ? 'true' : null\" (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu()\">\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 <div class=\"ag-header ag-header--pinned\" role=\"row\" aria-rowindex=\"1\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\" [style.width.px]=\"pinnedPaneWidth()\">\n @if (showControlColumn()) {\n <div class=\"ag-header-cell ag-control-header\" role=\"columnheader\" aria-colindex=\"1\">\n <div class=\"ag-header-cell-top\"></div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\"></div>\n }\n </div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [class.ag-header-cell--pinned-last]=\"isLastPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [itemSize]=\"rowHeight()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + 2\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isPinnedPaneRowSelected(item)\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\" (click)=\"$event.stopPropagation()\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\"></div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\" [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">{{\n getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + 2\"\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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">\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\">\n <div class=\"ag-header\" role=\"row\" aria-rowindex=\"1\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-header-cell\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [attr.data-col-field]=\"col.field\" (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">\u229F</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [itemSize]=\"rowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + 2\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 @for (col of scrollableColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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--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 (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-ghost-cell\">{{ getGhostCellDisplay(col) }}</div>\n }\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 </div>\n </div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + 2\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\">\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 <div class=\"ag-header\" role=\"row\" aria-rowindex=\"1\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\" [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">'\u229F '</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [itemSize]=\"rowHeight()\" [style.width.px]=\"rightPinnedPaneWidth()\" (scroll)=\"onRightPinnedBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + 2\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(item)\"\n [class.ag-row--odd]=\"isDataRowItem(item) && dataRowIsOdd().get(item.originalIndex) === true\"\n [class.ag-row--selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex)\"\n [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (col of rightPinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\n [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--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]=\"isFirstRightPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">{{ getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\" [attr.aria-rowindex]=\"displayItems().length + 2\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">\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\n [open]=\"sidebarOpen()\"\n [activeTab]=\"sidebarTab()\"\n [columns]=\"colDefs()\"\n [row]=\"sidebarRow()\"\n [hiddenColumns]=\"sidebarHiddenColumns()\"\n [locale]=\"locale()\"\n [localeText]=\"localeText()\"\n [readonlyGrid]=\"readonlyGrid()\"\n [useSidebarEditor]=\"useSidebarEditor()\"\n (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\"\n (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\"\n />\n }\n </div><!-- /.ag-main-area -->\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\"\n [disabled]=\"control()!.currentPage() <= 1\" (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\"\n [disabled]=\"control()!.currentPage() <= 1\" (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\"\n (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\"\n (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 <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 ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n </div>\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.value, col)\">{{ localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.row)\">{{ localeText().copyRow }}</button>\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 }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{ 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\"\n (click)=\"deleteRow(menu.rowIndex); closeCellContextMenu()\">{{ 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\" [disabled]=\"item.disabled\"\n (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]=\"sortOption() !== 'none'\"\n [showColumnActions]=\"!!control()\" [pinned]=\"getColumnPinState(menu.field)\"\n [groupable]=\"!!getColDef(menu.field)?.groupable\" [grouped]=\"isGroupedByField(menu.field)\"\n [filterable]=\"!!getColDef(menu.field)?.filterable\" [showValueFilter]=\"!serverSideFiltering()\"\n [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\"\n [valueItems]=\"serverSideFiltering() || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\"\n [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 (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\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}}: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-header{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-bottom:2px solid var(--agrid-color-border)}.ag-header-cell{position:relative;display:flex;align-items:center;font-weight:600;border-right:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;-webkit-user-select:none;user-select:none;box-sizing:border-box}.ag-header-cell:last-child{border-right:none}.ag-header-cell-top{display:flex;align-items:center;flex:1;min-width:0;padding:0 6px;height:32px;overflow:hidden;white-space:nowrap}.ag-header-cell-label{overflow:hidden;text-overflow:ellipsis;flex:1}.ag-header--with-filters .ag-header-cell{flex-direction:column;align-items:stretch;height:auto;white-space:normal}.ag-header--with-filters .ag-header-cell-top{flex:0 0 32px}.ag-header-cell-filter{height:28px;display:flex;align-items:center;padding:0 2px;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-header-cell{cursor:grab}.ag-header-cell--dragging{opacity:.45;cursor:grabbing}.ag-header-cell--drop-before{box-shadow:inset 2px 0 0 var(--agrid-color-accent)}.ag-header-cell--drop-after{box-shadow:inset -2px 0 0 var(--agrid-color-accent)}.ag-sort-badge{font-size:11px;color:var(--agrid-color-accent);flex-shrink:0;line-height:1}.ag-sort-priority{font-size:9px;vertical-align:super;opacity:.75}.ag-resize-handle{position:absolute;top:0;right:0;width:5px;height:100%;cursor:col-resize;z-index:1}.ag-resize-handle:hover{background:var(--agrid-color-accent);opacity:.5}.ag-filter-input{flex:1;min-width:0;height:20px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 4px;background:var(--agrid-color-bg)}.ag-filter-input:focus{border-color:var(--agrid-color-accent)}.ag-header-cell--filtered .ag-header-cell-label:after{content:\" \\25be\";font-size:9px;color:var(--agrid-color-accent)}.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}: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 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-header{z-index:3;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted)}.ag-control-header .ag-header-cell-filter{background:var(--agrid-color-bg-subtle)}.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;box-sizing:border-box}.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--reorder:after{content:\"\\283f\";font-size:13px;color:var(--agrid-color-border)}.ag-control-cell--reorder:hover:after{color:var(--agrid-color-text-muted)}.ag-control-cell--reorder:active{cursor:grabbing}.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-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-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-header-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-header-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-header-cell--pinned-first{box-shadow:none}.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-header-menu-btn{flex-shrink:0;width:16px;height:16px;padding:0;margin-right:2px;background:none;border:1px solid transparent;border-radius:3px;cursor:pointer;font-size:10px;color:var(--agrid-color-text-muted);display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity .12s;line-height:1}.ag-header-menu-btn--active{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle)}.ag-header-menu-btn:hover{background:var(--agrid-color-bg);border-color:var(--agrid-color-border)}\n"] }]
5253
+ }, 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\"\n [attr.aria-busy]=\"loading() ? 'true' : null\" (copy)=\"onCopy($event)\" (paste)=\"onPaste($event)\"\n (focusin)=\"onGridFocusIn($event)\"\n (click)=\"closeContextMenu(); closeCellContextMenu(); closeFilterMenu(); closeGroupActionsMenu()\">\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 @if (hasHeaderGroups()) {\n <div class=\"ag-header-groups ag-header-groups--pinned\" role=\"row\" aria-rowindex=\"1\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\" [style.width.px]=\"pinnedPaneWidth()\">\n @if (showControlColumn()) {\n <div class=\"ag-header-group-cell ag-header-group-cell--empty\"></div>\n }\n @for (run of pinnedHeaderGroupRuns(); track run.key) {\n <div class=\"ag-header-group-cell\" role=\"columnheader\"\n [attr.data-header-group]=\"run.id\"\n [class.ag-header-group-cell--empty]=\"!run.id\"\n [class.ag-header-group-cell--locked]=\"isHeaderGroupLocked(run.fields)\"\n [class.ag-header-group-cell--dragging]=\"isHeaderGroupDragging(run.fields)\"\n [style.grid-column]=\"'span ' + run.span\"\n (pointerdown)=\"run.id && onHeaderGroupPointerDown($event, run.fields, run.label)\">\n {{ run.label }}\n </div>\n }\n </div>\n }\n <div class=\"ag-header ag-header--pinned\" role=\"row\" [attr.aria-rowindex]=\"headerRowCount()\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"pinnedGridTemplateColumns()\" [style.width.px]=\"pinnedPaneWidth()\">\n @if (showControlColumn()) {\n <div class=\"ag-header-cell ag-control-header\" role=\"columnheader\" aria-colindex=\"1\">\n <div class=\"ag-header-cell-top\"></div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\"></div>\n }\n </div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-header-cell--pinned-last]=\"isLastPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #pinnedViewport class=\"ag-body ag-pinned-body\" [itemSize]=\"rowHeight()\"\n [style.width.px]=\"pinnedPaneWidth()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + headerRowCount() + 1\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\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 [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 (contextmenu)=\"onControlContextMenu($event, item.originalIndex)\" (click)=\"$event.stopPropagation()\"\n (pointerdown)=\"onControlPointerDown($event, item.originalIndex)\">\n @if (enableRowMarking()) {\n <input class=\"ag-row-marker\" type=\"checkbox\" [checked]=\"isRowMarked(item.originalIndex)\"\n [attr.aria-label]=\"localeText().markRow\"\n (pointerdown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRowMarked(item.originalIndex)\" />\n }\n </div>\n }\n @for (col of pinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class]=\"getCellClass(col, item.row[col.field], item.row)\" [class.ag-cell--pinned]=\"true\"\n [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">{{\n getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\"\n [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 (col of pinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-last]=\"isLastPinnedColumn(col.field)\">\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 @if (hasHeaderGroups()) {\n <div class=\"ag-header-groups\" role=\"row\" aria-rowindex=\"1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (run of scrollableHeaderGroupRuns(); track run.key) {\n <div class=\"ag-header-group-cell\" role=\"columnheader\"\n [attr.data-header-group]=\"run.id\"\n [class.ag-header-group-cell--empty]=\"!run.id\"\n [class.ag-header-group-cell--locked]=\"isHeaderGroupLocked(run.fields)\"\n [class.ag-header-group-cell--dragging]=\"isHeaderGroupDragging(run.fields)\"\n [style.grid-column]=\"'span ' + run.span\"\n (pointerdown)=\"run.id && onHeaderGroupPointerDown($event, run.fields, run.label)\">\n {{ run.label }}\n </div>\n }\n </div>\n }\n <div class=\"ag-header\" role=\"row\" [attr.aria-rowindex]=\"headerRowCount()\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-header-cell\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.data-col-field]=\"col.field\" (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">\u229F</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #scrollViewport class=\"ag-body\" [itemSize]=\"rowHeight()\"\n [style.min-width.px]=\"scrollableTotalWidth()\" (scroll)=\"onBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + headerRowCount() + 1\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(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)\"\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 [attr.data-original-index]=\"getItemOriginalIndex(item)\" [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(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 @for (col of scrollableColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\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-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + '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 (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\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 (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-ghost-cell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\">{{\n getGhostCellDisplay(col) }}</div>\n }\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 </div>\n </div>\n }\n @if (isDataRowItem(item) && isRowPendingDelete(item.originalIndex)) {\n <div class=\"ag-delete-confirmation\" role=\"alertdialog\"\n [attr.aria-label]=\"localeText().confirmDeleteRow\"\n [style.left.px]=\"deleteConfirmationLeft()\"\n [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\"\n type=\"button\" (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 </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\"\n [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"scrollableGridTemplateColumns()\"\n [style.min-width.px]=\"scrollableTotalWidth()\">\n @for (col of scrollableColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\">\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 @if (hasHeaderGroups()) {\n <div class=\"ag-header-groups\" role=\"row\" aria-rowindex=\"1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\" [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (run of rightHeaderGroupRuns(); track run.key) {\n <div class=\"ag-header-group-cell\" role=\"columnheader\"\n [attr.data-header-group]=\"run.id\"\n [class.ag-header-group-cell--empty]=\"!run.id\"\n [class.ag-header-group-cell--locked]=\"isHeaderGroupLocked(run.fields)\"\n [class.ag-header-group-cell--dragging]=\"isHeaderGroupDragging(run.fields)\"\n [style.grid-column]=\"'span ' + run.span\"\n (pointerdown)=\"run.id && onHeaderGroupPointerDown($event, run.fields, run.label)\">\n {{ run.label }}\n </div>\n }\n </div>\n }\n <div class=\"ag-header\" role=\"row\" [attr.aria-rowindex]=\"headerRowCount()\"\n [class.ag-header--with-filters]=\"hasFilterableColumns()\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\" [style.width.px]=\"rightPinnedPaneWidth()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-header-cell ag-header-cell--pinned\" role=\"columnheader\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [attr.aria-sort]=\"getSort(col.field) === 'asc' ? 'ascending' : getSort(col.field) === 'desc' ? 'descending' : 'none'\"\n [class.ag-header-cell--filtered]=\"hasActiveFilter(col.field)\"\n [class.ag-header-cell--dragging]=\"isColDragging(col.field)\"\n [class.ag-header-cell--drop-before]=\"getColDropSide(col.field) === 'before'\"\n [class.ag-header-cell--drop-after]=\"getColDropSide(col.field) === 'after'\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-header-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\" [attr.data-col-field]=\"col.field\"\n (pointerdown)=\"onColHeaderPointerDown($event, col.field)\">\n <div class=\"ag-header-cell-top\">\n <span class=\"ag-header-cell-label\">{{ col.header }}</span>\n @if (getSort(col.field); as dir) {\n <span class=\"ag-sort-badge\">{{ dir === 'asc' ? '\u2191' : '\u2193' }}@if (hasMultiSort()) {<sup\n class=\"ag-sort-priority\">{{ getSortPriority(col.field) }}</sup>}</span>\n }\n @if (isGroupedByField(col.field)) {\n <span class=\"ag-sort-badge\">'\u229F '</span>\n }\n <button class=\"ag-header-menu-btn\" [class.ag-header-menu-btn--active]=\"hasActiveFilter(col.field)\"\n [title]=\"localeText().columnMenu\" [attr.aria-label]=\"localeText().columnMenu + ': ' + col.header\"\n [attr.aria-expanded]=\"filterMenu()?.field === col.field\" aria-haspopup=\"menu\"\n (click)=\"openFilterMenu($event, col.field)\"\n (pointerdown)=\"$event.stopPropagation()\">\u25BE</button>\n </div>\n @if (hasFilterableColumns()) {\n <div class=\"ag-header-cell-filter\">\n @if (col.filterable) {\n <input class=\"ag-filter-input\" [value]=\"getTextFilter(col.field)\"\n (input)=\"onTextFilterChange($event, col.field)\" (click)=\"$event.stopPropagation()\"\n [placeholder]=\"localeText().filterPlaceholder\"\n [attr.aria-label]=\"localeText().filterPlaceholder + ' ' + col.header\" />\n }\n </div>\n }\n <div class=\"ag-resize-handle\" role=\"separator\" [attr.tabindex]=\"col.locked ? -1 : 0\"\n aria-orientation=\"vertical\" [attr.aria-disabled]=\"col.locked ? 'true' : null\"\n [attr.aria-label]=\"localeText().resizeColumn + ': ' + col.header\"\n [attr.aria-valuenow]=\"getColumnWidth(col)\" (keydown)=\"onResizeKeyDown($event, col)\"\n (mousedown)=\"onResizeStart($event, col)\"\n (pointerdown)=\"$event.stopPropagation()\" (dblclick)=\"onAutosizeColumn($event, col)\"></div>\n </div>\n }\n </div>\n\n <cdk-virtual-scroll-viewport #rightPinnedViewport class=\"ag-body ag-pinned-body ag-right-pinned-body\"\n [itemSize]=\"rowHeight()\" [style.width.px]=\"rightPinnedPaneWidth()\" (scroll)=\"onRightPinnedBodyScroll()\">\n <div *cdkVirtualFor=\"let item of displayItems(); let di = index; trackBy: trackByItem\" role=\"row\"\n [attr.aria-rowindex]=\"di + headerRowCount() + 1\"\n [attr.aria-selected]=\"isDataRowItem(item) && isRowSelected(item.originalIndex) ? 'true' : null\"\n [class.ag-row]=\"!isGroupHeaderItem(item)\" [class.ag-add-row]=\"item === null\"\n [class.ag-ghost-row]=\"item === 'ghost'\" [class.ag-group-header-row]=\"isGroupHeaderItem(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 [style.height.px]=\"rowHeight()\"\n [style.grid-template-columns]=\"isDataRowItem(item) || item === 'ghost' ? rightGridTemplateColumns() : null\">\n @if (isDataRowItem(item)) {\n @for (col of rightPinnedColDefs(); track col.field) {\n @let ci = getVisibleColIndex(col.field);\n <agrid-cell [col]=\"col\" [rowIndex]=\"item.originalIndex\" [colIndex]=\"ci\" [value]=\"item.row[col.field]\"\n [row]=\"item.row\" [locale]=\"locale()\" [attr.title]=\"getCellTitle(col, item.row[col.field])\"\n [attr.data-cell-row]=\"item.originalIndex\" [attr.data-cell-col]=\"ci\"\n [attr.data-col-field]=\"col.field\"\n [attr.aria-colindex]=\"getAriaColIndex(ci)\"\n [attr.aria-selected]=\"isSelected(item.originalIndex, ci) || isRangeSelected(item.originalIndex, ci)\"\n [selected]=\"isSelected(item.originalIndex, ci)\" [editing]=\"isEditing(item.originalIndex, ci)\"\n [seedChar]=\"getSeedChar(item.originalIndex, ci)\"\n [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-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + '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]=\"isFirstRightPinnedColumn(col.field)\"\n (pointerdown)=\"onCellPointerDown($event, item.originalIndex, ci)\"\n (activate)=\"onActivate(item.originalIndex, ci, $event)\" (startEdit)=\"onStartEdit(item.originalIndex, ci)\"\n (draftChange)=\"onDraftChange($event)\"\n (contextmenu)=\"onCellContextMenu($event, item.originalIndex, ci, col, item.row)\" />\n }\n } @else if (item === null) {\n <div class=\"ag-pinned-row-spacer\"></div>\n } @else if (item === 'ghost') {\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-ghost-cell ag-cell--pinned\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [class.ag-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">{{ getGhostCellDisplay(col) }}</div>\n }\n } @else {\n <div class=\"ag-pinned-group-spacer\"></div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n\n @if (showFooter()) {\n <div class=\"ag-footer\" role=\"row\"\n [attr.aria-rowindex]=\"displayItems().length + headerRowCount() + 1\"\n [style.grid-template-columns]=\"rightGridTemplateColumns()\">\n @for (col of rightPinnedColDefs(); track col.field) {\n <div class=\"ag-footer-cell\" role=\"gridcell\"\n [class.ag-column-reorder-item--dragging]=\"isColDragging(col.field)\"\n [style.transform]=\"'translateX(' + getColReorderOffset(col.field) + 'px)'\"\n [attr.aria-colindex]=\"getAriaColIndex(getVisibleColIndex(col.field))\"\n [class.ag-footer-cell--pinned-first]=\"isFirstRightPinnedColumn(col.field)\">\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\n [open]=\"sidebarOpen()\"\n [activeTab]=\"sidebarTab()\"\n [columns]=\"colDefs()\"\n [row]=\"sidebarRow()\"\n [hiddenColumns]=\"sidebarHiddenColumns()\"\n [locale]=\"locale()\"\n [localeText]=\"localeText()\"\n [readonlyGrid]=\"readonlyGrid()\"\n [useSidebarEditor]=\"useSidebarEditor()\"\n (close)=\"toggleSidebar()\"\n (tabChange)=\"onSidebarStripClick($event)\"\n (toggleColumn)=\"onSidebarToggleColumn($event)\"\n (detailEdit)=\"onSidebarDetailEdit($event)\"\n (save)=\"onSidebarDetailSave($event)\"\n />\n }\n </div><!-- /.ag-main-area -->\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\"\n [disabled]=\"control()!.currentPage() <= 1\" (click)=\"goToFirstPage()\">\u00AB</button>\n <button class=\"ag-page-btn\" [attr.aria-label]=\"localeText().previous\"\n [disabled]=\"control()!.currentPage() <= 1\" (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\"\n (click)=\"goToNextPage()\">\u203A</button>\n <button class=\"ag-page-btn\" [disabled]=\"control()!.currentPage() >= totalPages()\"\n [attr.aria-label]=\"localeText().lastPage\"\n (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 <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 ag-context-item--danger\" role=\"menuitem\" (click)=\"deleteRow(menu.rowIndex)\">\n {{ localeText().deleteRow }}\n </button>\n </div>\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)\">{{ localeText().copyCellValue\n }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"copyRowToClipboard(menu.rowIndex)\">{{ localeText().copyRow }}</button>\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 }}</button>\n <button class=\"ag-context-item\" role=\"menuitem\" (click)=\"insertRowAt(menu.rowIndex + 1)\">{{ 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\"\n (click)=\"deleteRow(menu.rowIndex)\">{{ 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\" [disabled]=\"item.disabled\"\n (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]=\"sortOption() !== 'none'\"\n [showColumnActions]=\"!!control()\" [pinned]=\"getColumnPinState(menu.field)\"\n [groupable]=\"!!getColDef(menu.field)?.groupable\" [grouped]=\"isGroupedByField(menu.field)\"\n [filterable]=\"!!getColDef(menu.field)?.filterable\" [showValueFilter]=\"!serverSideFiltering()\"\n [search]=\"filterMenuSearch()\"\n [allSelected]=\"isMenuAllSelected(menu.field)\"\n [valueItems]=\"serverSideFiltering() || !getColDef(menu.field)?.filterable ? [] : columnMenuValueItems()\"\n [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 (setAggregate)=\"onMenuSetAggregate(menu.field, $event)\" />\n }\n\n @if (columnDragPreview(); as preview) {\n <div class=\"ag-column-drag-preview\"\n [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}}: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-header{display:grid;flex-shrink:0;background:var(--agrid-color-bg-muted);border-bottom:2px solid var(--agrid-color-border)}.ag-header-groups{display:grid;flex-shrink:0;height:28px;background:color-mix(in srgb,var(--agrid-color-bg-muted) 72%,var(--agrid-color-bg));border-bottom:1px solid var(--agrid-color-border)}.ag-header-group-cell{display:flex;align-items:center;justify-content:center;min-width:0;padding:0 8px;overflow:hidden;border-right:1px solid var(--agrid-color-border);box-sizing:border-box;color:var(--agrid-color-text);font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap;cursor:grab;-webkit-user-select:none;user-select:none;transition:opacity .1s ease}.ag-header-group-cell:last-child{border-right:none}.ag-header-group-cell--empty,.ag-header-group-cell--locked{cursor:default}.ag-header-group-cell--dragging{opacity:.12}.ag-header-cell{position:relative;display:flex;align-items:center;font-weight:600;border-right:1px solid var(--agrid-color-border);overflow:hidden;white-space:nowrap;-webkit-user-select:none;user-select:none;box-sizing:border-box}.ag-header-cell:last-child{border-right:none}.ag-header-cell-top{display:flex;align-items:center;flex:1;min-width:0;padding:0 6px;height:32px;overflow:hidden;white-space:nowrap}.ag-header-cell-label{overflow:hidden;text-overflow:ellipsis;flex:1}.ag-header--with-filters .ag-header-cell{flex-direction:column;align-items:stretch;height:auto;white-space:normal}.ag-header--with-filters .ag-header-cell-top{flex:0 0 32px}.ag-header-cell-filter{height:28px;display:flex;align-items:center;padding:0 2px;border-top:1px solid var(--agrid-color-border);background:var(--agrid-color-bg)}.ag-header-cell{cursor:grab;transition:transform .16s cubic-bezier(.2,0,0,1),opacity .1s ease;will-change:transform}.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-header-cell--dragging{opacity:.12;cursor:grabbing}.ag-column-reorder-item--dragging{opacity:.12}.ag-header-cell--drop-before,.ag-header-cell--drop-after{z-index:1}.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-sort-badge{font-size:11px;color:var(--agrid-color-accent);flex-shrink:0;line-height:1}.ag-sort-priority{font-size:9px;vertical-align:super;opacity:.75}.ag-resize-handle{position:absolute;top:0;right:0;width:5px;height:100%;cursor:col-resize;z-index:1}.ag-resize-handle:hover{background:var(--agrid-color-accent);opacity:.5}.ag-filter-input{flex:1;min-width:0;height:20px;border:1px solid var(--agrid-color-border);border-radius:3px;outline:none;font:inherit;font-size:12px;padding:0 4px;background:var(--agrid-color-bg)}.ag-filter-input:focus{border-color:var(--agrid-color-accent)}.ag-header-cell--filtered .ag-header-cell-label:after{content:\" \\25be\";font-size:9px;color:var(--agrid-color-accent)}.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}.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--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-header{z-index:3;border-right:1px solid var(--agrid-color-border);background:var(--agrid-color-bg-muted)}.ag-control-header .ag-header-cell-filter{background:var(--agrid-color-bg-subtle)}.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--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-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-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-header-cell--pinned{background:var(--agrid-color-bg-muted)}.ag-header-cell--pinned-last{box-shadow:inset -1px 0 0 var(--agrid-color-border),3px 0 6px -2px var(--agrid-color-shadow)}.ag-header-cell--pinned-first{box-shadow:none}.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-header-menu-btn{flex-shrink:0;width:16px;height:16px;padding:0;margin-right:2px;background:none;border:1px solid transparent;border-radius:3px;cursor:pointer;font-size:10px;color:var(--agrid-color-text-muted);display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity .12s;line-height:1}.ag-header-menu-btn--active{color:var(--agrid-color-accent);border-color:var(--agrid-color-accent-border);background:var(--agrid-color-accent-subtle)}.ag-header-menu-btn:hover{background:var(--agrid-color-bg);border-color:var(--agrid-color-border)}\n"] }]
4789
5254
  }], 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"] }], rowDoubleClicked: [{ type: i0.Output, args: ["rowDoubleClicked"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], rowChanged: [{ type: i0.Output, args: ["rowChanged"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], 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 }] }] } });
4790
5255
 
4791
5256
  /** Width sentinel that makes a column fill the remaining horizontal space. */