@gp-grid/angular 0.16.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { input, output, computed, TemplateRef, ChangeDetectionStrategy, Component, ViewChild, signal, effect, HostListener, inject, PLATFORM_ID, InjectionToken, Injectable } from '@angular/core';
3
3
  import { NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
4
- import { getFieldValue, isCellSelected, isCellActive, formatCellValue, isCellInFillPreview, buildCellClasses, isCellEditing, calculateFilterPopupPosition, calculateScaledColumnPositions, getTotalWidth, calculateFillHandlePosition, DataSourceOwner, AutoScrollDriver, PendingRowDragController, InputEventAdapter, applyBatchInstructions, scrollCellIntoView, GridCore, createMutableClientDataSource } from '@gp-grid/core';
4
+ import { getFieldValue, isCellSelected, isCellActive, formatCellValue, isCellInFillPreview, buildCellClasses, isCellEditing, calculateFilterPopupPosition, bindPeekSelectAll, calculateScaledColumnPositions, getTotalWidth, calculateFillHandlePosition, DataSourceOwner, AutoScrollDriver, PendingRowDragController, PendingCellTapController, TouchScrollController, InputEventAdapter, applyBatchInstructions, scrollCellIntoView, GridCore, createMutableClientDataSource } from '@gp-grid/core';
5
5
  export { GridCore, createClientDataSource, createDataSourceFromArray, createMutableClientDataSource, createServerDataSource } from '@gp-grid/core';
6
6
 
7
- const TEMPLATE$1 = `
7
+ const TEMPLATE$2 = `
8
8
  <div
9
9
  class="gp-grid-header"
10
10
  [class.gp-grid-header--loading]="isLoading()"
@@ -153,7 +153,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
153
153
  standalone: true,
154
154
  imports: [NgTemplateOutlet],
155
155
  changeDetection: ChangeDetectionStrategy.OnPush,
156
- template: TEMPLATE$1,
156
+ template: TEMPLATE$2,
157
157
  }]
158
158
  }], propDecorators: { headerHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerHeight", required: true }] }], scrollLeft: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollLeft", required: true }] }], contentWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentWidth", required: true }] }], totalWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalWidth", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: true }] }], visibleColumnsWithIndices: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleColumnsWithIndices", required: true }] }], columnPositions: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnPositions", required: true }] }], columnWidths: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnWidths", required: true }] }], headers: [{ type: i0.Input, args: [{ isSignal: true, alias: "headers", required: true }] }], sortingEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortingEnabled", required: false }] }], headerRenderers: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerRenderers", required: false }] }], globalHeaderRenderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalHeaderRenderer", required: false }] }], headerPointerDown: [{ type: i0.Output, args: ["headerPointerDown"] }], filterPointerDown: [{ type: i0.Output, args: ["filterPointerDown"] }], resizePointerDown: [{ type: i0.Output, args: ["resizePointerDown"] }], headerSort: [{ type: i0.Output, args: ["headerSort"] }], headerFilterOpen: [{ type: i0.Output, args: ["headerFilterOpen"] }] } });
159
159
 
@@ -183,8 +183,8 @@ const GRID_BODY_TEMPLATE = `<div
183
183
  <div
184
184
  [class]="cellClass(slot.rowIndex, entry.originalIndex, entry.column, slot.rowData)"
185
185
  style="position: absolute; top: 0;"
186
- [attr.data-row-index]="slot.rowIndex"
187
- [attr.data-col-index]="entry.originalIndex"
186
+ [attr.data-cell-row]="slot.rowIndex"
187
+ [attr.data-cell-col]="entry.originalIndex"
188
188
  [style.left.px]="columnPositions()[i]"
189
189
  [style.width.px]="columnWidths()[i]"
190
190
  [style.height.px]="rowHeight()"
@@ -428,7 +428,7 @@ class GridBodyComponent {
428
428
  }
429
429
  }
430
430
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GridBodyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
431
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: GridBodyComponent, isStandalone: true, selector: "gp-grid-body", inputs: { rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: true, transformFunction: null }, totalHeaderHeight: { classPropertyName: "totalHeaderHeight", publicName: "totalHeaderHeight", isSignal: true, isRequired: true, transformFunction: null }, contentWidth: { classPropertyName: "contentWidth", publicName: "contentWidth", isSignal: true, isRequired: true, transformFunction: null }, contentHeight: { classPropertyName: "contentHeight", publicName: "contentHeight", isSignal: true, isRequired: true, transformFunction: null }, rowsWrapperOffset: { classPropertyName: "rowsWrapperOffset", publicName: "rowsWrapperOffset", isSignal: true, isRequired: true, transformFunction: null }, slotsArray: { classPropertyName: "slotsArray", publicName: "slotsArray", isSignal: true, isRequired: true, transformFunction: null }, visibleColumnWithIndices: { classPropertyName: "visibleColumnWithIndices", publicName: "visibleColumnWithIndices", isSignal: true, isRequired: true, transformFunction: null }, totalWidth: { classPropertyName: "totalWidth", publicName: "totalWidth", isSignal: true, isRequired: true, transformFunction: null }, columnPositions: { classPropertyName: "columnPositions", publicName: "columnPositions", isSignal: true, isRequired: true, transformFunction: null }, columnWidths: { classPropertyName: "columnWidths", publicName: "columnWidths", isSignal: true, isRequired: true, transformFunction: null }, totalRows: { classPropertyName: "totalRows", publicName: "totalRows", isSignal: true, isRequired: true, transformFunction: null }, activeCell: { classPropertyName: "activeCell", publicName: "activeCell", isSignal: true, isRequired: false, transformFunction: null }, selectionRange: { classPropertyName: "selectionRange", publicName: "selectionRange", isSignal: true, isRequired: false, transformFunction: null }, editingCell: { classPropertyName: "editingCell", publicName: "editingCell", isSignal: true, isRequired: false, transformFunction: null }, cellRenderers: { classPropertyName: "cellRenderers", publicName: "cellRenderers", isSignal: true, isRequired: false, transformFunction: null }, globalCellRenderer: { classPropertyName: "globalCellRenderer", publicName: "globalCellRenderer", isSignal: true, isRequired: false, transformFunction: null }, editRenderers: { classPropertyName: "editRenderers", publicName: "editRenderers", isSignal: true, isRequired: false, transformFunction: null }, globalEditRenderer: { classPropertyName: "globalEditRenderer", publicName: "globalEditRenderer", isSignal: true, isRequired: false, transformFunction: null }, hoverPosition: { classPropertyName: "hoverPosition", publicName: "hoverPosition", isSignal: true, isRequired: false, transformFunction: null }, computeRowClasses: { classPropertyName: "computeRowClasses", publicName: "computeRowClasses", isSignal: true, isRequired: false, transformFunction: null }, computeCellClasses: { classPropertyName: "computeCellClasses", publicName: "computeCellClasses", isSignal: true, isRequired: false, transformFunction: null }, fillHandlePosition: { classPropertyName: "fillHandlePosition", publicName: "fillHandlePosition", isSignal: true, isRequired: false, transformFunction: null }, dragState: { classPropertyName: "dragState", publicName: "dragState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scrolled: "scrolled", cellPointerDown: "cellPointerDown", cellPointerEnter: "cellPointerEnter", cellPointerLeave: "cellPointerLeave", cellDoubleClick: "cellDoubleClick", editValueChange: "editValueChange", editCommit: "editCommit", editCancel: "editCancel", fillHandlePointerDown: "fillHandlePointerDown" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], ngImport: i0, template: "<div\n #scrollContainer\n style=\"height: 100%; overflow: auto; position: relative;\"\n (scroll)=\"onScroll()\">\n <div\n style=\"position: relative; min-width: 100%\"\n [style.width.px]=\"innerWidth()\"\n [style.height.px]=\"sizerHeight()\">\n <div\n class=\"gp-grid-rows-wrapper\"\n [style.width.px]=\"innerWidth()\"\n [style.transform]=\"wrapperTransform()\">\n @for (slot of slotsArray(); track slot.slotId) {\n @if (slot.rowIndex >= 0) {\n <div\n [class]=\"rowClass(slot.rowIndex, slot.rowData)\"\n style=\"position: absolute; top: 0; left: 0\"\n [style.transform]=\"'translateY(' + slot.translateY + 'px)'\"\n [style.width.px]=\"innerWidth()\"\n [style.height.px]=\"rowHeight()\"\n >\n @for (entry of visibleColumnWithIndices(); track entry.originalIndex; let i = $index) {\n @let editing = isEditing(slot.rowIndex, entry.originalIndex);\n <div\n [class]=\"cellClass(slot.rowIndex, entry.originalIndex, entry.column, slot.rowData)\"\n style=\"position: absolute; top: 0;\"\n [attr.data-row-index]=\"slot.rowIndex\"\n [attr.data-col-index]=\"entry.originalIndex\"\n [style.left.px]=\"columnPositions()[i]\"\n [style.width.px]=\"columnWidths()[i]\"\n [style.height.px]=\"rowHeight()\"\n (pointerdown)=\"cellPointerDown.emit({ rowIndex: slot.rowIndex, colIndex: entry.originalIndex, event: $event })\"\n (mouseenter)=\"cellPointerEnter.emit({ rowIndex: slot.rowIndex, colIndex: entry.originalIndex })\"\n (mouseleave)=\"cellPointerLeave.emit()\"\n (dblclick)=\"cellDoubleClick.emit({ rowIndex: slot.rowIndex, colIndex: entry.originalIndex })\"\n >\n @if (editing) {\n @let etpl = editTemplate(entry.column);\n @if (etpl) {\n <ng-container\n [ngTemplateOutlet]=\"etpl\"\n [ngTemplateOutletContext]=\"{ $implicit: editParams(slot.rowData, entry.column, slot.rowIndex, entry.originalIndex) }\">\n </ng-container>\n } @else {\n <input\n class=\"gp-grid-edit-input\"\n type=\"text\"\n [value]=\"editInitialValue()\"\n autofocus\n (focus)=\"onEditFocus($event)\"\n (input)=\"editValueChange.emit(asInput($event).value)\"\n (keydown)=\"onEditKeyDown($event)\"\n (blur)=\"editCommit.emit()\" />\n }\n } @else {\n @let tpl = cellTemplate(entry.column);\n @if (tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: cellParams(slot.rowData, entry.column, slot.rowIndex, entry.originalIndex) }\">\n </ng-container>\n } @else {\n {{ cellDisplay(slot.rowData, entry.column, slot.rowIndex, entry.originalIndex) }}\n }\n }\n </div>\n }\n </div>\n }\n }\n @if (fillHandlePosition(); as fhp) {\n @if (editingCell() === null) {\n <div\n class=\"gp-grid-fill-handle\"\n [style.top.px]=\"fhp.top\"\n [style.left.px]=\"fhp.left\"\n (pointerdown)=\"fillHandlePointerDown.emit({ event: $event })\">\n </div>\n }\n }\n @if (rowDropIndicator(); as rd) {\n <div\n class=\"gp-grid-row-drop-indicator\"\n [style.transform]=\"'translateY(' + rd.dropIndicatorY + 'px)'\"\n [style.width.px]=\"rowDropIndicatorWidth()\"></div>\n }\n </div>\n </div>\n @if (totalRows() === 0) {\n <div class=\"gp-grid-empty\">No data to display</div>\n }\n </div>\n", isInline: true, styles: [":host{display:flex;flex:1;min-height:0;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
431
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: GridBodyComponent, isStandalone: true, selector: "gp-grid-body", inputs: { rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: true, transformFunction: null }, totalHeaderHeight: { classPropertyName: "totalHeaderHeight", publicName: "totalHeaderHeight", isSignal: true, isRequired: true, transformFunction: null }, contentWidth: { classPropertyName: "contentWidth", publicName: "contentWidth", isSignal: true, isRequired: true, transformFunction: null }, contentHeight: { classPropertyName: "contentHeight", publicName: "contentHeight", isSignal: true, isRequired: true, transformFunction: null }, rowsWrapperOffset: { classPropertyName: "rowsWrapperOffset", publicName: "rowsWrapperOffset", isSignal: true, isRequired: true, transformFunction: null }, slotsArray: { classPropertyName: "slotsArray", publicName: "slotsArray", isSignal: true, isRequired: true, transformFunction: null }, visibleColumnWithIndices: { classPropertyName: "visibleColumnWithIndices", publicName: "visibleColumnWithIndices", isSignal: true, isRequired: true, transformFunction: null }, totalWidth: { classPropertyName: "totalWidth", publicName: "totalWidth", isSignal: true, isRequired: true, transformFunction: null }, columnPositions: { classPropertyName: "columnPositions", publicName: "columnPositions", isSignal: true, isRequired: true, transformFunction: null }, columnWidths: { classPropertyName: "columnWidths", publicName: "columnWidths", isSignal: true, isRequired: true, transformFunction: null }, totalRows: { classPropertyName: "totalRows", publicName: "totalRows", isSignal: true, isRequired: true, transformFunction: null }, activeCell: { classPropertyName: "activeCell", publicName: "activeCell", isSignal: true, isRequired: false, transformFunction: null }, selectionRange: { classPropertyName: "selectionRange", publicName: "selectionRange", isSignal: true, isRequired: false, transformFunction: null }, editingCell: { classPropertyName: "editingCell", publicName: "editingCell", isSignal: true, isRequired: false, transformFunction: null }, cellRenderers: { classPropertyName: "cellRenderers", publicName: "cellRenderers", isSignal: true, isRequired: false, transformFunction: null }, globalCellRenderer: { classPropertyName: "globalCellRenderer", publicName: "globalCellRenderer", isSignal: true, isRequired: false, transformFunction: null }, editRenderers: { classPropertyName: "editRenderers", publicName: "editRenderers", isSignal: true, isRequired: false, transformFunction: null }, globalEditRenderer: { classPropertyName: "globalEditRenderer", publicName: "globalEditRenderer", isSignal: true, isRequired: false, transformFunction: null }, hoverPosition: { classPropertyName: "hoverPosition", publicName: "hoverPosition", isSignal: true, isRequired: false, transformFunction: null }, computeRowClasses: { classPropertyName: "computeRowClasses", publicName: "computeRowClasses", isSignal: true, isRequired: false, transformFunction: null }, computeCellClasses: { classPropertyName: "computeCellClasses", publicName: "computeCellClasses", isSignal: true, isRequired: false, transformFunction: null }, fillHandlePosition: { classPropertyName: "fillHandlePosition", publicName: "fillHandlePosition", isSignal: true, isRequired: false, transformFunction: null }, dragState: { classPropertyName: "dragState", publicName: "dragState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scrolled: "scrolled", cellPointerDown: "cellPointerDown", cellPointerEnter: "cellPointerEnter", cellPointerLeave: "cellPointerLeave", cellDoubleClick: "cellDoubleClick", editValueChange: "editValueChange", editCommit: "editCommit", editCancel: "editCancel", fillHandlePointerDown: "fillHandlePointerDown" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], ngImport: i0, template: "<div\n #scrollContainer\n style=\"height: 100%; overflow: auto; position: relative;\"\n (scroll)=\"onScroll()\">\n <div\n style=\"position: relative; min-width: 100%\"\n [style.width.px]=\"innerWidth()\"\n [style.height.px]=\"sizerHeight()\">\n <div\n class=\"gp-grid-rows-wrapper\"\n [style.width.px]=\"innerWidth()\"\n [style.transform]=\"wrapperTransform()\">\n @for (slot of slotsArray(); track slot.slotId) {\n @if (slot.rowIndex >= 0) {\n <div\n [class]=\"rowClass(slot.rowIndex, slot.rowData)\"\n style=\"position: absolute; top: 0; left: 0\"\n [style.transform]=\"'translateY(' + slot.translateY + 'px)'\"\n [style.width.px]=\"innerWidth()\"\n [style.height.px]=\"rowHeight()\"\n >\n @for (entry of visibleColumnWithIndices(); track entry.originalIndex; let i = $index) {\n @let editing = isEditing(slot.rowIndex, entry.originalIndex);\n <div\n [class]=\"cellClass(slot.rowIndex, entry.originalIndex, entry.column, slot.rowData)\"\n style=\"position: absolute; top: 0;\"\n [attr.data-cell-row]=\"slot.rowIndex\"\n [attr.data-cell-col]=\"entry.originalIndex\"\n [style.left.px]=\"columnPositions()[i]\"\n [style.width.px]=\"columnWidths()[i]\"\n [style.height.px]=\"rowHeight()\"\n (pointerdown)=\"cellPointerDown.emit({ rowIndex: slot.rowIndex, colIndex: entry.originalIndex, event: $event })\"\n (mouseenter)=\"cellPointerEnter.emit({ rowIndex: slot.rowIndex, colIndex: entry.originalIndex })\"\n (mouseleave)=\"cellPointerLeave.emit()\"\n (dblclick)=\"cellDoubleClick.emit({ rowIndex: slot.rowIndex, colIndex: entry.originalIndex })\"\n >\n @if (editing) {\n @let etpl = editTemplate(entry.column);\n @if (etpl) {\n <ng-container\n [ngTemplateOutlet]=\"etpl\"\n [ngTemplateOutletContext]=\"{ $implicit: editParams(slot.rowData, entry.column, slot.rowIndex, entry.originalIndex) }\">\n </ng-container>\n } @else {\n <input\n class=\"gp-grid-edit-input\"\n type=\"text\"\n [value]=\"editInitialValue()\"\n autofocus\n (focus)=\"onEditFocus($event)\"\n (input)=\"editValueChange.emit(asInput($event).value)\"\n (keydown)=\"onEditKeyDown($event)\"\n (blur)=\"editCommit.emit()\" />\n }\n } @else {\n @let tpl = cellTemplate(entry.column);\n @if (tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: cellParams(slot.rowData, entry.column, slot.rowIndex, entry.originalIndex) }\">\n </ng-container>\n } @else {\n {{ cellDisplay(slot.rowData, entry.column, slot.rowIndex, entry.originalIndex) }}\n }\n }\n </div>\n }\n </div>\n }\n }\n @if (fillHandlePosition(); as fhp) {\n @if (editingCell() === null) {\n <div\n class=\"gp-grid-fill-handle\"\n [style.top.px]=\"fhp.top\"\n [style.left.px]=\"fhp.left\"\n (pointerdown)=\"fillHandlePointerDown.emit({ event: $event })\">\n </div>\n }\n }\n @if (rowDropIndicator(); as rd) {\n <div\n class=\"gp-grid-row-drop-indicator\"\n [style.transform]=\"'translateY(' + rd.dropIndicatorY + 'px)'\"\n [style.width.px]=\"rowDropIndicatorWidth()\"></div>\n }\n </div>\n </div>\n @if (totalRows() === 0) {\n <div class=\"gp-grid-empty\">No data to display</div>\n }\n </div>\n", isInline: true, styles: [":host{display:flex;flex:1;min-height:0;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
432
432
  }
433
433
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GridBodyComponent, decorators: [{
434
434
  type: Component,
@@ -994,7 +994,7 @@ const setField = (arr, index, key, value) => {
994
994
  item[key] = value;
995
995
  };
996
996
 
997
- const TEMPLATE = `
997
+ const TEMPLATE$1 = `
998
998
  @if (filterPopup(); as fp) {
999
999
  <gp-grid-filter-popup
1000
1000
  [column]="fp.column"
@@ -1107,10 +1107,163 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
1107
1107
  standalone: true,
1108
1108
  imports: [FilterPopupComponent],
1109
1109
  changeDetection: ChangeDetectionStrategy.OnPush,
1110
- template: TEMPLATE,
1110
+ template: TEMPLATE$1,
1111
1111
  }]
1112
1112
  }], propDecorators: { filterPopup: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPopup", required: false }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], headerHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerHeight", required: true }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: true }] }], dragState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragState", required: true }] }], visibleColumnWithIndices: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleColumnWithIndices", required: true }] }], columnPositions: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnPositions", required: true }] }], scrollLeft: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollLeft", required: true }] }], effectiveColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "effectiveColumns", required: true }] }], totalWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalWidth", required: true }] }], filterApply: [{ type: i0.Output, args: ["filterApply"] }], filterClose: [{ type: i0.Output, args: ["filterClose"] }] } });
1113
1113
 
1114
+ const TEMPLATE = `
1115
+ <div
1116
+ #overlayEl
1117
+ class="gp-grid-cell-peek"
1118
+ [style.position]="'fixed'"
1119
+ [style.top.px]="top()"
1120
+ [style.left.px]="left()"
1121
+ [style.width.px]="width()"
1122
+ [style.visibility]="positioned() ? 'visible' : 'hidden'">
1123
+ @if (template(); as tpl) {
1124
+ <ng-container
1125
+ [ngTemplateOutlet]="tpl"
1126
+ [ngTemplateOutletContext]="{ $implicit: rendererParams() }">
1127
+ </ng-container>
1128
+ } @else {
1129
+ {{ fallbackText() }}
1130
+ }
1131
+ </div>
1132
+ `;
1133
+ class CellPeekComponent {
1134
+ overlayEl;
1135
+ peekCell = input.required(...(ngDevMode ? [{ debugName: "peekCell" }] : /* istanbul ignore next */ []));
1136
+ column = input.required(...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
1137
+ rowData = input.required(...(ngDevMode ? [{ debugName: "rowData" }] : /* istanbul ignore next */ []));
1138
+ containerEl = input.required(...(ngDevMode ? [{ debugName: "containerEl" }] : /* istanbul ignore next */ []));
1139
+ cellRenderers = input({}, ...(ngDevMode ? [{ debugName: "cellRenderers" }] : /* istanbul ignore next */ []));
1140
+ globalCellRenderer = input(null, ...(ngDevMode ? [{ debugName: "globalCellRenderer" }] : /* istanbul ignore next */ []));
1141
+ close = output();
1142
+ top = signal(0, ...(ngDevMode ? [{ debugName: "top" }] : /* istanbul ignore next */ []));
1143
+ left = signal(0, ...(ngDevMode ? [{ debugName: "left" }] : /* istanbul ignore next */ []));
1144
+ width = signal(0, ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
1145
+ positioned = signal(false, ...(ngDevMode ? [{ debugName: "positioned" }] : /* istanbul ignore next */ []));
1146
+ template = computed(() => {
1147
+ const renderer = this.column().cellRenderer;
1148
+ if (renderer instanceof TemplateRef)
1149
+ return renderer;
1150
+ if (typeof renderer === 'string') {
1151
+ const registered = this.cellRenderers()[renderer];
1152
+ if (registered)
1153
+ return registered;
1154
+ }
1155
+ return this.globalCellRenderer();
1156
+ }, ...(ngDevMode ? [{ debugName: "template" }] : /* istanbul ignore next */ []));
1157
+ rendererParams = computed(() => {
1158
+ const col = this.column();
1159
+ const data = this.rowData();
1160
+ const rawValue = getFieldValue(data, col.field);
1161
+ const displayValue = col.valueFormatter ? col.valueFormatter(rawValue) : rawValue;
1162
+ return {
1163
+ value: displayValue,
1164
+ rowData: data,
1165
+ column: col,
1166
+ rowIndex: this.peekCell().row,
1167
+ colIndex: this.peekCell().col,
1168
+ isActive: true,
1169
+ isSelected: false,
1170
+ isEditing: false,
1171
+ };
1172
+ }, ...(ngDevMode ? [{ debugName: "rendererParams" }] : /* istanbul ignore next */ []));
1173
+ fallbackText = computed(() => {
1174
+ const col = this.column();
1175
+ const renderer = col.cellRenderer;
1176
+ const value = getFieldValue(this.rowData(), col.field);
1177
+ if (typeof renderer === 'function') {
1178
+ const result = renderer(this.rendererParams());
1179
+ return result === null || result === undefined ? '' : String(result);
1180
+ }
1181
+ return formatCellValue(value, col.valueFormatter);
1182
+ }, ...(ngDevMode ? [{ debugName: "fallbackText" }] : /* istanbul ignore next */ []));
1183
+ rafId = null;
1184
+ pointerRafId = null;
1185
+ unbindSelectAll = null;
1186
+ constructor() {
1187
+ effect(() => {
1188
+ this.peekCell();
1189
+ this.updatePosition();
1190
+ });
1191
+ }
1192
+ ngAfterViewInit() {
1193
+ this.updatePosition();
1194
+ window.addEventListener('scroll', this.onWindowScrollOrResize, { passive: true, capture: true });
1195
+ window.addEventListener('resize', this.onWindowScrollOrResize);
1196
+ if (this.overlayEl?.nativeElement) {
1197
+ this.unbindSelectAll = bindPeekSelectAll(this.overlayEl.nativeElement);
1198
+ }
1199
+ this.pointerRafId = requestAnimationFrame(() => {
1200
+ document.addEventListener('pointerdown', this.onDocumentPointerDown);
1201
+ });
1202
+ }
1203
+ ngOnDestroy() {
1204
+ window.removeEventListener('scroll', this.onWindowScrollOrResize, { capture: true });
1205
+ window.removeEventListener('resize', this.onWindowScrollOrResize);
1206
+ document.removeEventListener('pointerdown', this.onDocumentPointerDown);
1207
+ this.unbindSelectAll?.();
1208
+ if (this.rafId !== null)
1209
+ cancelAnimationFrame(this.rafId);
1210
+ if (this.pointerRafId !== null)
1211
+ cancelAnimationFrame(this.pointerRafId);
1212
+ }
1213
+ onEscape() {
1214
+ this.close.emit();
1215
+ }
1216
+ updatePosition() {
1217
+ const container = this.containerEl();
1218
+ const overlay = this.overlayEl?.nativeElement;
1219
+ if (!container || !overlay)
1220
+ return;
1221
+ const peek = this.peekCell();
1222
+ const cellEl = container.querySelector(`[data-cell-row="${peek.row}"][data-cell-col="${peek.col}"]`);
1223
+ if (!cellEl) {
1224
+ this.close.emit();
1225
+ return;
1226
+ }
1227
+ const rect = cellEl.getBoundingClientRect();
1228
+ this.top.set(rect.top);
1229
+ this.left.set(rect.left);
1230
+ this.width.set(rect.width);
1231
+ this.positioned.set(true);
1232
+ }
1233
+ onWindowScrollOrResize = () => {
1234
+ if (this.rafId !== null)
1235
+ return;
1236
+ this.rafId = requestAnimationFrame(() => {
1237
+ this.rafId = null;
1238
+ this.updatePosition();
1239
+ });
1240
+ };
1241
+ onDocumentPointerDown = (event) => {
1242
+ const target = event.target;
1243
+ if (this.overlayEl?.nativeElement?.contains(target))
1244
+ return;
1245
+ this.close.emit();
1246
+ };
1247
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CellPeekComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1248
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: CellPeekComponent, isStandalone: true, selector: "gp-grid-cell-peek", inputs: { peekCell: { classPropertyName: "peekCell", publicName: "peekCell", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, rowData: { classPropertyName: "rowData", publicName: "rowData", isSignal: true, isRequired: true, transformFunction: null }, containerEl: { classPropertyName: "containerEl", publicName: "containerEl", isSignal: true, isRequired: true, transformFunction: null }, cellRenderers: { classPropertyName: "cellRenderers", publicName: "cellRenderers", isSignal: true, isRequired: false, transformFunction: null }, globalCellRenderer: { classPropertyName: "globalCellRenderer", publicName: "globalCellRenderer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close" }, host: { listeners: { "keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "overlayEl", first: true, predicate: ["overlayEl"], descendants: true }], ngImport: i0, template: "\n <div\n #overlayEl\n class=\"gp-grid-cell-peek\"\n [style.position]=\"'fixed'\"\n [style.top.px]=\"top()\"\n [style.left.px]=\"left()\"\n [style.width.px]=\"width()\"\n [style.visibility]=\"positioned() ? 'visible' : 'hidden'\">\n @if (template(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: rendererParams() }\">\n </ng-container>\n } @else {\n {{ fallbackText() }}\n }\n </div>\n", isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1249
+ }
1250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CellPeekComponent, decorators: [{
1251
+ type: Component,
1252
+ args: [{
1253
+ selector: 'gp-grid-cell-peek',
1254
+ standalone: true,
1255
+ imports: [NgTemplateOutlet],
1256
+ changeDetection: ChangeDetectionStrategy.OnPush,
1257
+ template: TEMPLATE,
1258
+ }]
1259
+ }], ctorParameters: () => [], propDecorators: { overlayEl: [{
1260
+ type: ViewChild,
1261
+ args: ['overlayEl', { static: false }]
1262
+ }], peekCell: [{ type: i0.Input, args: [{ isSignal: true, alias: "peekCell", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], rowData: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowData", required: true }] }], containerEl: [{ type: i0.Input, args: [{ isSignal: true, alias: "containerEl", required: true }] }], cellRenderers: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellRenderers", required: false }] }], globalCellRenderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalCellRenderer", required: false }] }], close: [{ type: i0.Output, args: ["close"] }], onEscape: [{
1263
+ type: HostListener,
1264
+ args: ['keydown.escape']
1265
+ }] } });
1266
+
1114
1267
  const GP_GRID_TEMPLATE = `
1115
1268
  <div #container
1116
1269
  [class]="'gp-grid-container' + (darkMode() ? ' gp-grid-container--dark' : '')"
@@ -1187,6 +1340,17 @@ const GP_GRID_TEMPLATE = `
1187
1340
  (filterApply)="onFilterApply($event)"
1188
1341
  (filterClose)="onFilterClose()"
1189
1342
  />
1343
+ @if (peekContext(); as ctx) {
1344
+ <gp-grid-cell-peek
1345
+ [peekCell]="ctx.peek"
1346
+ [column]="ctx.column"
1347
+ [rowData]="ctx.rowData"
1348
+ [containerEl]="container"
1349
+ [cellRenderers]="cellRenderers()"
1350
+ [globalCellRenderer]="cellRenderer()"
1351
+ (close)="onPeekClose()"
1352
+ />
1353
+ }
1190
1354
  </div>
1191
1355
  `;
1192
1356
 
@@ -1221,6 +1385,7 @@ class GpGridViewModel {
1221
1385
  selectionRange = signal(null, ...(ngDevMode ? [{ debugName: "selectionRange" }] : /* istanbul ignore next */ []));
1222
1386
  editingCell = signal(null, ...(ngDevMode ? [{ debugName: "editingCell" }] : /* istanbul ignore next */ []));
1223
1387
  hoverPosition = signal(null, ...(ngDevMode ? [{ debugName: "hoverPosition" }] : /* istanbul ignore next */ []));
1388
+ peekCell = signal(null, ...(ngDevMode ? [{ debugName: "peekCell" }] : /* istanbul ignore next */ []));
1224
1389
  columnsOverride = signal(null, ...(ngDevMode ? [{ debugName: "columnsOverride" }] : /* istanbul ignore next */ []));
1225
1390
  dragState = signal(INITIAL_DRAG_STATE, ...(ngDevMode ? [{ debugName: "dragState" }] : /* istanbul ignore next */ []));
1226
1391
  contentWidth = signal(0, ...(ngDevMode ? [{ debugName: "contentWidth" }] : /* istanbul ignore next */ []));
@@ -1269,6 +1434,7 @@ class GpGridViewModel {
1269
1434
  setSelectionRange: (v) => this.selectionRange.set(v),
1270
1435
  setEditingCell: (v) => this.editingCell.set(v),
1271
1436
  setHoverPosition: (v) => this.hoverPosition.set(v),
1437
+ setPeekCell: (v) => this.peekCell.set(v),
1272
1438
  setColumnsOverride: (v) => this.columnsOverride.set(v),
1273
1439
  onFilterPopupChange: (v) => this.materializeFilterPopup(v),
1274
1440
  };
@@ -1304,6 +1470,8 @@ class GpGridBindings {
1304
1470
  dataSourceOwner = new DataSourceOwner();
1305
1471
  autoScroll;
1306
1472
  pendingRowDrag;
1473
+ pendingCellTap;
1474
+ touchScroll;
1307
1475
  input;
1308
1476
  coreRef = null;
1309
1477
  unsubscribe = null;
@@ -1317,11 +1485,22 @@ class GpGridBindings {
1317
1485
  isBrowser: this.deps.isBrowser,
1318
1486
  onDragConfirmed: (state) => this.deps.vm.dragState.set(state),
1319
1487
  });
1488
+ this.pendingCellTap = new PendingCellTapController({
1489
+ getCore: () => this.coreRef,
1490
+ isBrowser: this.deps.isBrowser,
1491
+ onTapConfirmed: () => this.deps.getContainer()?.focus(),
1492
+ });
1493
+ this.touchScroll = new TouchScrollController({
1494
+ getCore: () => this.coreRef,
1495
+ getScrollEl: this.deps.getBody,
1496
+ isBrowser: this.deps.isBrowser,
1497
+ });
1320
1498
  this.input = new InputEventAdapter({
1321
1499
  getCore: () => this.coreRef,
1322
1500
  getBodyEl: this.deps.getBody,
1323
1501
  autoScroll: this.autoScroll,
1324
1502
  pendingRowDrag: this.pendingRowDrag,
1503
+ pendingCellTap: this.pendingCellTap,
1325
1504
  onDragStateChange: (state) => this.deps.vm.dragState.set(state),
1326
1505
  });
1327
1506
  }
@@ -1351,11 +1530,16 @@ class GpGridBindings {
1351
1530
  });
1352
1531
  this.resizeObserver.observe(container);
1353
1532
  this.coreRef?.setViewport(0, 0, container.clientWidth, bodyEl.clientHeight);
1533
+ // Synthetic touch scrolling: takes over touch gestures only when scroll
1534
+ // virtualization compresses the DOM scroll space; inert otherwise.
1535
+ this.touchScroll.attach();
1354
1536
  }
1355
1537
  destroy() {
1356
1538
  this.autoScroll.stop();
1357
1539
  this.pendingRowDrag.cancel();
1358
1540
  this.pendingRowDrag.releaseLocks();
1541
+ this.pendingCellTap.cancel();
1542
+ this.touchScroll.detach();
1359
1543
  this.unsubscribe?.();
1360
1544
  this.resizeObserver?.disconnect();
1361
1545
  this.coreRef?.destroy();
@@ -1387,16 +1571,22 @@ class GpGridBindings {
1387
1571
  const top = this.deps.vm.pendingScrollTop();
1388
1572
  const body = this.deps.getBody();
1389
1573
  if (top !== null && body) {
1574
+ this.touchScroll.stop();
1390
1575
  body.scrollTop = top;
1391
1576
  this.deps.vm.pendingScrollTop.set(null);
1392
1577
  }
1393
1578
  }
1394
- scrollToRow(row) {
1579
+ scrollToCell(cell) {
1395
1580
  const core = this.coreRef;
1396
1581
  const body = this.deps.getBody();
1397
1582
  if (core === null || body === null)
1398
1583
  return;
1399
- scrollCellIntoView(core, body, row, this.deps.getRowHeight(), this.deps.vm.slots(), this.deps.vm.rowsWrapperOffset());
1584
+ scrollCellIntoView(core, body, cell.row, this.deps.getRowHeight(), this.deps.vm.slots(), this.deps.vm.rowsWrapperOffset(), {
1585
+ colIndex: cell.col,
1586
+ visibleColumns: this.deps.vm.visibleColumnWithIndices(),
1587
+ columnPositions: this.deps.vm.columnPositions(),
1588
+ columnWidths: this.deps.vm.columnWidths(),
1589
+ });
1400
1590
  }
1401
1591
  }
1402
1592
 
@@ -1550,8 +1740,23 @@ class GpGridComponent {
1550
1740
  return this.bindings.coreRef?.highlight?.computeCombinedCellClasses(rowIndex, colIndex, column, rowData) ?? [];
1551
1741
  };
1552
1742
  onCellDoubleClick(evt) {
1553
- this.bindings.coreRef?.startEdit(evt.rowIndex, evt.colIndex);
1743
+ this.bindings.coreRef?.input.handleCellDoubleClick(evt.rowIndex, evt.colIndex);
1744
+ }
1745
+ onPeekClose() {
1746
+ this.bindings.coreRef?.stopPeek();
1554
1747
  }
1748
+ peekContext = computed(() => {
1749
+ const peek = this.vm.peekCell();
1750
+ if (peek === null)
1751
+ return null;
1752
+ const column = this.vm.effectiveColumns()[peek.col];
1753
+ if (!column)
1754
+ return null;
1755
+ const slot = [...this.vm.slots().values()].find((s) => s.rowIndex === peek.row);
1756
+ if (!slot)
1757
+ return null;
1758
+ return { peek, column, rowData: slot.rowData };
1759
+ }, ...(ngDevMode ? [{ debugName: "peekContext" }] : /* istanbul ignore next */ []));
1555
1760
  onEditValueChange(value) {
1556
1761
  this.bindings.coreRef?.updateEditValue(value);
1557
1762
  }
@@ -1581,7 +1786,7 @@ class GpGridComponent {
1581
1786
  if (result.preventDefault)
1582
1787
  event.preventDefault();
1583
1788
  if (result.scrollToCell)
1584
- this.bindings.scrollToRow(result.scrollToCell.row);
1789
+ this.bindings.scrollToCell(result.scrollToCell);
1585
1790
  }
1586
1791
  onPaste(event) {
1587
1792
  const editing = this.vm.editingCell();
@@ -1612,11 +1817,11 @@ class GpGridComponent {
1612
1817
  this.bindings.pendingRowDrag.releaseLocks();
1613
1818
  };
1614
1819
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GpGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1615
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.7", type: GpGridComponent, isStandalone: true, selector: "gp-grid", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, getRowId: { classPropertyName: "getRowId", publicName: "getRowId", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, headerHeight: { classPropertyName: "headerHeight", publicName: "headerHeight", isSignal: true, isRequired: false, transformFunction: null }, darkMode: { classPropertyName: "darkMode", publicName: "darkMode", isSignal: true, isRequired: false, transformFunction: null }, cellRenderers: { classPropertyName: "cellRenderers", publicName: "cellRenderers", isSignal: true, isRequired: false, transformFunction: null }, headerRenderers: { classPropertyName: "headerRenderers", publicName: "headerRenderers", isSignal: true, isRequired: false, transformFunction: null }, editRenderers: { classPropertyName: "editRenderers", publicName: "editRenderers", isSignal: true, isRequired: false, transformFunction: null }, cellRenderer: { classPropertyName: "cellRenderer", publicName: "cellRenderer", isSignal: true, isRequired: false, transformFunction: null }, headerRenderer: { classPropertyName: "headerRenderer", publicName: "headerRenderer", isSignal: true, isRequired: false, transformFunction: null }, editRenderer: { classPropertyName: "editRenderer", publicName: "editRenderer", isSignal: true, isRequired: false, transformFunction: null }, highlighting: { classPropertyName: "highlighting", publicName: "highlighting", isSignal: true, isRequired: false, transformFunction: null }, rowDragEntireRow: { classPropertyName: "rowDragEntireRow", publicName: "rowDragEntireRow", isSignal: true, isRequired: false, transformFunction: null }, overscan: { classPropertyName: "overscan", publicName: "overscan", isSignal: true, isRequired: false, transformFunction: null }, rowLoading: { classPropertyName: "rowLoading", publicName: "rowLoading", isSignal: true, isRequired: false, transformFunction: null }, sortingEnabled: { classPropertyName: "sortingEnabled", publicName: "sortingEnabled", isSignal: true, isRequired: false, transformFunction: null }, wheelDampening: { classPropertyName: "wheelDampening", publicName: "wheelDampening", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRowDragEnd: "onRowDragEnd", onCellValueChanged: "onCellValueChanged", onColumnResized: "onColumnResized", onColumnMoved: "onColumnMoved" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }, { propertyName: "body", first: true, predicate: GridBodyComponent, descendants: true }], ngImport: i0, template: "\n <div #container\n [class]=\"'gp-grid-container' + (darkMode() ? ' gp-grid-container--dark' : '')\"\n style=\"width: 100%; height: 100%; display: flex; flex-direction: column; position: relative; outline: none;\"\n tabindex=\"0\"\n (keydown)=\"onKeyDown($event)\"\n (paste)=\"onPaste($event)\"\n (wheel)=\"onWheel($event)\"\n >\n <gp-grid-header\n [headerHeight]=\"headerHeight()\"\n [scrollLeft]=\"vm.scrollLeft()\"\n [contentWidth]=\"vm.contentWidth()\"\n [totalWidth]=\"vm.totalWidth()\"\n [isLoading]=\"vm.isLoading()\"\n [visibleColumnsWithIndices]=\"vm.visibleColumnWithIndices()\"\n [columnPositions]=\"vm.columnPositions()\"\n [columnWidths]=\"vm.columnWidths()\"\n [headers]=\"vm.headerState()\"\n [sortingEnabled]=\"sortingEnabled()\"\n [headerRenderers]=\"headerRenderers()\"\n [globalHeaderRenderer]=\"headerRenderer()\"\n (headerPointerDown)=\"onHeaderPointerDown($event)\"\n (filterPointerDown)=\"onFilterPointerDown($event)\"\n (resizePointerDown)=\"onResizePointerDown($event)\"\n (headerSort)=\"onHeaderSort($event)\"\n />\n <gp-grid-body\n [rowHeight]=\"rowHeight()\"\n [totalHeaderHeight]=\"headerHeight()\"\n [contentWidth]=\"vm.contentWidth()\"\n [contentHeight]=\"vm.contentHeight()\"\n [totalWidth]=\"vm.totalWidth()\"\n [rowsWrapperOffset]=\"vm.rowsWrapperOffset()\"\n [slotsArray]=\"vm.slotsArray()\"\n [visibleColumnWithIndices]=\"vm.visibleColumnWithIndices()\"\n [columnPositions]=\"vm.columnPositions()\"\n [columnWidths]=\"vm.columnWidths()\"\n [totalRows]=\"vm.totalRows()\"\n [activeCell]=\"vm.activeCell()\"\n [selectionRange]=\"vm.selectionRange()\"\n [editingCell]=\"vm.editingCell()\"\n [cellRenderers]=\"cellRenderers()\"\n [globalCellRenderer]=\"cellRenderer()\"\n [editRenderers]=\"editRenderers()\"\n [globalEditRenderer]=\"editRenderer()\"\n [hoverPosition]=\"vm.hoverPosition()\"\n [computeRowClasses]=\"computeRowClassesFn\"\n [computeCellClasses]=\"computeCellClassesFn\"\n [fillHandlePosition]=\"vm.fillHandlePosition()\"\n [dragState]=\"vm.dragState()\"\n (scrolled)=\"onBodyScroll($event)\"\n (cellPointerDown)=\"onCellPointerDown($event)\"\n (cellPointerEnter)=\"onCellPointerEnter($event)\"\n (cellPointerLeave)=\"onCellPointerLeave()\"\n (cellDoubleClick)=\"onCellDoubleClick($event)\"\n (editValueChange)=\"onEditValueChange($event)\"\n (editCommit)=\"onEditCommit()\"\n (editCancel)=\"onEditCancel()\"\n (fillHandlePointerDown)=\"onFillHandlePointerDown($event)\"\n />\n <gp-grid-overlays\n [filterPopup]=\"vm.filterPopup()\"\n [isLoading]=\"vm.isLoading()\"\n [errorMessage]=\"vm.errorMessage()\"\n [headerHeight]=\"headerHeight()\"\n [rowHeight]=\"rowHeight()\"\n [dragState]=\"vm.dragState()\"\n [visibleColumnWithIndices]=\"vm.visibleColumnWithIndices()\"\n [columnPositions]=\"vm.columnPositions()\"\n [scrollLeft]=\"vm.scrollLeft()\"\n [effectiveColumns]=\"vm.effectiveColumns()\"\n [totalWidth]=\"vm.totalWidth()\"\n (filterApply)=\"onFilterApply($event)\"\n (filterClose)=\"onFilterClose()\"\n />\n </div>\n ", isInline: true, styles: [":host{display:block;height:100%;min-height:0}\n"], dependencies: [{ kind: "component", type: GridHeaderComponent, selector: "gp-grid-header", inputs: ["headerHeight", "scrollLeft", "contentWidth", "totalWidth", "isLoading", "visibleColumnsWithIndices", "columnPositions", "columnWidths", "headers", "sortingEnabled", "headerRenderers", "globalHeaderRenderer"], outputs: ["headerPointerDown", "filterPointerDown", "resizePointerDown", "headerSort", "headerFilterOpen"] }, { kind: "component", type: GridBodyComponent, selector: "gp-grid-body", inputs: ["rowHeight", "totalHeaderHeight", "contentWidth", "contentHeight", "rowsWrapperOffset", "slotsArray", "visibleColumnWithIndices", "totalWidth", "columnPositions", "columnWidths", "totalRows", "activeCell", "selectionRange", "editingCell", "cellRenderers", "globalCellRenderer", "editRenderers", "globalEditRenderer", "hoverPosition", "computeRowClasses", "computeCellClasses", "fillHandlePosition", "dragState"], outputs: ["scrolled", "cellPointerDown", "cellPointerEnter", "cellPointerLeave", "cellDoubleClick", "editValueChange", "editCommit", "editCancel", "fillHandlePointerDown"] }, { kind: "component", type: GridOverlaysComponent, selector: "gp-grid-overlays", inputs: ["filterPopup", "isLoading", "errorMessage", "headerHeight", "rowHeight", "dragState", "visibleColumnWithIndices", "columnPositions", "scrollLeft", "effectiveColumns", "totalWidth"], outputs: ["filterApply", "filterClose"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1820
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: GpGridComponent, isStandalone: true, selector: "gp-grid", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, getRowId: { classPropertyName: "getRowId", publicName: "getRowId", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, headerHeight: { classPropertyName: "headerHeight", publicName: "headerHeight", isSignal: true, isRequired: false, transformFunction: null }, darkMode: { classPropertyName: "darkMode", publicName: "darkMode", isSignal: true, isRequired: false, transformFunction: null }, cellRenderers: { classPropertyName: "cellRenderers", publicName: "cellRenderers", isSignal: true, isRequired: false, transformFunction: null }, headerRenderers: { classPropertyName: "headerRenderers", publicName: "headerRenderers", isSignal: true, isRequired: false, transformFunction: null }, editRenderers: { classPropertyName: "editRenderers", publicName: "editRenderers", isSignal: true, isRequired: false, transformFunction: null }, cellRenderer: { classPropertyName: "cellRenderer", publicName: "cellRenderer", isSignal: true, isRequired: false, transformFunction: null }, headerRenderer: { classPropertyName: "headerRenderer", publicName: "headerRenderer", isSignal: true, isRequired: false, transformFunction: null }, editRenderer: { classPropertyName: "editRenderer", publicName: "editRenderer", isSignal: true, isRequired: false, transformFunction: null }, highlighting: { classPropertyName: "highlighting", publicName: "highlighting", isSignal: true, isRequired: false, transformFunction: null }, rowDragEntireRow: { classPropertyName: "rowDragEntireRow", publicName: "rowDragEntireRow", isSignal: true, isRequired: false, transformFunction: null }, overscan: { classPropertyName: "overscan", publicName: "overscan", isSignal: true, isRequired: false, transformFunction: null }, rowLoading: { classPropertyName: "rowLoading", publicName: "rowLoading", isSignal: true, isRequired: false, transformFunction: null }, sortingEnabled: { classPropertyName: "sortingEnabled", publicName: "sortingEnabled", isSignal: true, isRequired: false, transformFunction: null }, wheelDampening: { classPropertyName: "wheelDampening", publicName: "wheelDampening", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRowDragEnd: "onRowDragEnd", onCellValueChanged: "onCellValueChanged", onColumnResized: "onColumnResized", onColumnMoved: "onColumnMoved" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }, { propertyName: "body", first: true, predicate: GridBodyComponent, descendants: true }], ngImport: i0, template: "\n <div #container\n [class]=\"'gp-grid-container' + (darkMode() ? ' gp-grid-container--dark' : '')\"\n style=\"width: 100%; height: 100%; display: flex; flex-direction: column; position: relative; outline: none;\"\n tabindex=\"0\"\n (keydown)=\"onKeyDown($event)\"\n (paste)=\"onPaste($event)\"\n (wheel)=\"onWheel($event)\"\n >\n <gp-grid-header\n [headerHeight]=\"headerHeight()\"\n [scrollLeft]=\"vm.scrollLeft()\"\n [contentWidth]=\"vm.contentWidth()\"\n [totalWidth]=\"vm.totalWidth()\"\n [isLoading]=\"vm.isLoading()\"\n [visibleColumnsWithIndices]=\"vm.visibleColumnWithIndices()\"\n [columnPositions]=\"vm.columnPositions()\"\n [columnWidths]=\"vm.columnWidths()\"\n [headers]=\"vm.headerState()\"\n [sortingEnabled]=\"sortingEnabled()\"\n [headerRenderers]=\"headerRenderers()\"\n [globalHeaderRenderer]=\"headerRenderer()\"\n (headerPointerDown)=\"onHeaderPointerDown($event)\"\n (filterPointerDown)=\"onFilterPointerDown($event)\"\n (resizePointerDown)=\"onResizePointerDown($event)\"\n (headerSort)=\"onHeaderSort($event)\"\n />\n <gp-grid-body\n [rowHeight]=\"rowHeight()\"\n [totalHeaderHeight]=\"headerHeight()\"\n [contentWidth]=\"vm.contentWidth()\"\n [contentHeight]=\"vm.contentHeight()\"\n [totalWidth]=\"vm.totalWidth()\"\n [rowsWrapperOffset]=\"vm.rowsWrapperOffset()\"\n [slotsArray]=\"vm.slotsArray()\"\n [visibleColumnWithIndices]=\"vm.visibleColumnWithIndices()\"\n [columnPositions]=\"vm.columnPositions()\"\n [columnWidths]=\"vm.columnWidths()\"\n [totalRows]=\"vm.totalRows()\"\n [activeCell]=\"vm.activeCell()\"\n [selectionRange]=\"vm.selectionRange()\"\n [editingCell]=\"vm.editingCell()\"\n [cellRenderers]=\"cellRenderers()\"\n [globalCellRenderer]=\"cellRenderer()\"\n [editRenderers]=\"editRenderers()\"\n [globalEditRenderer]=\"editRenderer()\"\n [hoverPosition]=\"vm.hoverPosition()\"\n [computeRowClasses]=\"computeRowClassesFn\"\n [computeCellClasses]=\"computeCellClassesFn\"\n [fillHandlePosition]=\"vm.fillHandlePosition()\"\n [dragState]=\"vm.dragState()\"\n (scrolled)=\"onBodyScroll($event)\"\n (cellPointerDown)=\"onCellPointerDown($event)\"\n (cellPointerEnter)=\"onCellPointerEnter($event)\"\n (cellPointerLeave)=\"onCellPointerLeave()\"\n (cellDoubleClick)=\"onCellDoubleClick($event)\"\n (editValueChange)=\"onEditValueChange($event)\"\n (editCommit)=\"onEditCommit()\"\n (editCancel)=\"onEditCancel()\"\n (fillHandlePointerDown)=\"onFillHandlePointerDown($event)\"\n />\n <gp-grid-overlays\n [filterPopup]=\"vm.filterPopup()\"\n [isLoading]=\"vm.isLoading()\"\n [errorMessage]=\"vm.errorMessage()\"\n [headerHeight]=\"headerHeight()\"\n [rowHeight]=\"rowHeight()\"\n [dragState]=\"vm.dragState()\"\n [visibleColumnWithIndices]=\"vm.visibleColumnWithIndices()\"\n [columnPositions]=\"vm.columnPositions()\"\n [scrollLeft]=\"vm.scrollLeft()\"\n [effectiveColumns]=\"vm.effectiveColumns()\"\n [totalWidth]=\"vm.totalWidth()\"\n (filterApply)=\"onFilterApply($event)\"\n (filterClose)=\"onFilterClose()\"\n />\n @if (peekContext(); as ctx) {\n <gp-grid-cell-peek\n [peekCell]=\"ctx.peek\"\n [column]=\"ctx.column\"\n [rowData]=\"ctx.rowData\"\n [containerEl]=\"container\"\n [cellRenderers]=\"cellRenderers()\"\n [globalCellRenderer]=\"cellRenderer()\"\n (close)=\"onPeekClose()\"\n />\n }\n </div>\n ", isInline: true, styles: [":host{display:block;height:100%;min-height:0}\n"], dependencies: [{ kind: "component", type: GridHeaderComponent, selector: "gp-grid-header", inputs: ["headerHeight", "scrollLeft", "contentWidth", "totalWidth", "isLoading", "visibleColumnsWithIndices", "columnPositions", "columnWidths", "headers", "sortingEnabled", "headerRenderers", "globalHeaderRenderer"], outputs: ["headerPointerDown", "filterPointerDown", "resizePointerDown", "headerSort", "headerFilterOpen"] }, { kind: "component", type: GridBodyComponent, selector: "gp-grid-body", inputs: ["rowHeight", "totalHeaderHeight", "contentWidth", "contentHeight", "rowsWrapperOffset", "slotsArray", "visibleColumnWithIndices", "totalWidth", "columnPositions", "columnWidths", "totalRows", "activeCell", "selectionRange", "editingCell", "cellRenderers", "globalCellRenderer", "editRenderers", "globalEditRenderer", "hoverPosition", "computeRowClasses", "computeCellClasses", "fillHandlePosition", "dragState"], outputs: ["scrolled", "cellPointerDown", "cellPointerEnter", "cellPointerLeave", "cellDoubleClick", "editValueChange", "editCommit", "editCancel", "fillHandlePointerDown"] }, { kind: "component", type: GridOverlaysComponent, selector: "gp-grid-overlays", inputs: ["filterPopup", "isLoading", "errorMessage", "headerHeight", "rowHeight", "dragState", "visibleColumnWithIndices", "columnPositions", "scrollLeft", "effectiveColumns", "totalWidth"], outputs: ["filterApply", "filterClose"] }, { kind: "component", type: CellPeekComponent, selector: "gp-grid-cell-peek", inputs: ["peekCell", "column", "rowData", "containerEl", "cellRenderers", "globalCellRenderer"], outputs: ["close"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1616
1821
  }
1617
1822
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GpGridComponent, decorators: [{
1618
1823
  type: Component,
1619
- args: [{ selector: 'gp-grid', standalone: true, imports: [GridHeaderComponent, GridBodyComponent, GridOverlaysComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: GP_GRID_TEMPLATE, styles: [":host{display:block;height:100%;min-height:0}\n"] }]
1824
+ args: [{ selector: 'gp-grid', standalone: true, imports: [GridHeaderComponent, GridBodyComponent, GridOverlaysComponent, CellPeekComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: GP_GRID_TEMPLATE, styles: [":host{display:block;height:100%;min-height:0}\n"] }]
1620
1825
  }], ctorParameters: () => [], propDecorators: { container: [{
1621
1826
  type: ViewChild,
1622
1827
  args: ['container', { static: true }]
@@ -1761,5 +1966,5 @@ const provideGridData = (options) => [
1761
1966
  * Generated bundle index. Do not edit.
1762
1967
  */
1763
1968
 
1764
- export { FilterPopupComponent, GRID_DATA_OPTIONS, GpGridComponent, GridBodyComponent, GridDataService, GridHeaderComponent, GridOverlaysComponent, createGridData, injectGridData, provideGridData };
1969
+ export { CellPeekComponent, FilterPopupComponent, GRID_DATA_OPTIONS, GpGridComponent, GridBodyComponent, GridDataService, GridHeaderComponent, GridOverlaysComponent, createGridData, injectGridData, provideGridData };
1765
1970
  //# sourceMappingURL=gp-grid-angular.mjs.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gp-grid/angular",
3
3
  "description": "A high-performance Angular data grid component with virtual scrolling, cell selection, sorting, filtering, and Excel-like editing",
4
- "version": "0.16.1",
4
+ "version": "0.18.0",
5
5
  "license": "Apache-2.0",
6
6
  "module": "fesm2022/gp-grid-angular.mjs",
7
7
  "typings": "types/gp-grid-angular.d.ts",
@@ -51,7 +51,7 @@
51
51
  "@angular/core": ">=18.0.0"
52
52
  },
53
53
  "dependencies": {
54
- "@gp-grid/core": "0.16.1",
54
+ "@gp-grid/core": "0.18.0",
55
55
  "tslib": "^2.8.1"
56
56
  },
57
57
  "sideEffects": false,
@@ -1,8 +1,8 @@
1
- import * as _angular_core from '@angular/core';
2
- import { TemplateRef, ElementRef, AfterViewInit, OnDestroy, Signal, OnInit, InjectionToken, Provider } from '@angular/core';
3
1
  import * as _gp_grid_core from '@gp-grid/core';
4
2
  import { HeaderRendererParams, SortDirection, VisibleColumnInfo, HeaderData, ColumnDefinition, SlotData, CellPosition, CellRange, CellValue, CellRendererParams, EditRendererParams, FillHandlePosition, DragState, ColumnFilterModel, BatchChangeSetters, DataSource, RowId, HighlightingOptions, RowLoadingOptions, CellValueChangedEvent, ParallelSortOptions, MutableDataSource } from '@gp-grid/core';
5
3
  export { CellDataType, CellPosition, CellRange, CellRendererParams, CellValue, CellValueChangedEvent, ColumnDefinition, ColumnFilterModel, DataSource, DataSourceLoadMode, DataSourceRange, DataSourceRequest, DataSourceResponse, EditRendererParams, FilterCondition, FilterModel, GridCore, GridInstruction, HeaderRendererParams, HighlightContext, HighlightingOptions, MutableDataSource, RowCacheEviction, RowCacheOptions, RowId, RowLoadingMode, RowLoadingOptions, SortDirection, SortModel, createClientDataSource, createDataSourceFromArray, createMutableClientDataSource, createServerDataSource } from '@gp-grid/core';
4
+ import * as _angular_core from '@angular/core';
5
+ import { TemplateRef, ElementRef, AfterViewInit, OnDestroy, Signal, OnInit, InjectionToken, Provider } from '@angular/core';
6
6
 
7
7
  type HeaderRendererTemplate = TemplateRef<{
8
8
  $implicit: HeaderRendererParams;
@@ -260,6 +260,36 @@ declare class GridOverlaysComponent {
260
260
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<GridOverlaysComponent, "gp-grid-overlays", never, { "filterPopup": { "alias": "filterPopup"; "required": false; "isSignal": true; }; "isLoading": { "alias": "isLoading"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "headerHeight": { "alias": "headerHeight"; "required": true; "isSignal": true; }; "rowHeight": { "alias": "rowHeight"; "required": true; "isSignal": true; }; "dragState": { "alias": "dragState"; "required": true; "isSignal": true; }; "visibleColumnWithIndices": { "alias": "visibleColumnWithIndices"; "required": true; "isSignal": true; }; "columnPositions": { "alias": "columnPositions"; "required": true; "isSignal": true; }; "scrollLeft": { "alias": "scrollLeft"; "required": true; "isSignal": true; }; "effectiveColumns": { "alias": "effectiveColumns"; "required": true; "isSignal": true; }; "totalWidth": { "alias": "totalWidth"; "required": true; "isSignal": true; }; }, { "filterApply": "filterApply"; "filterClose": "filterClose"; }, never, never, true, never>;
261
261
  }
262
262
 
263
+ declare class CellPeekComponent implements AfterViewInit, OnDestroy {
264
+ overlayEl: ElementRef<HTMLDivElement>;
265
+ peekCell: _angular_core.InputSignal<CellPosition>;
266
+ column: _angular_core.InputSignal<ColumnDefinition>;
267
+ rowData: _angular_core.InputSignal<unknown>;
268
+ containerEl: _angular_core.InputSignal<HTMLElement>;
269
+ cellRenderers: _angular_core.InputSignal<Record<string, CellRendererTemplate>>;
270
+ globalCellRenderer: _angular_core.InputSignal<CellRendererTemplate>;
271
+ close: _angular_core.OutputEmitterRef<void>;
272
+ protected top: _angular_core.WritableSignal<number>;
273
+ protected left: _angular_core.WritableSignal<number>;
274
+ protected width: _angular_core.WritableSignal<number>;
275
+ protected positioned: _angular_core.WritableSignal<boolean>;
276
+ protected template: _angular_core.Signal<CellRendererTemplate>;
277
+ protected rendererParams: _angular_core.Signal<CellRendererParams<unknown>>;
278
+ protected fallbackText: _angular_core.Signal<string>;
279
+ private rafId;
280
+ private pointerRafId;
281
+ private unbindSelectAll;
282
+ constructor();
283
+ ngAfterViewInit(): void;
284
+ ngOnDestroy(): void;
285
+ onEscape(): void;
286
+ private updatePosition;
287
+ private onWindowScrollOrResize;
288
+ private onDocumentPointerDown;
289
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<CellPeekComponent, never>;
290
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CellPeekComponent, "gp-grid-cell-peek", never, { "peekCell": { "alias": "peekCell"; "required": true; "isSignal": true; }; "column": { "alias": "column"; "required": true; "isSignal": true; }; "rowData": { "alias": "rowData"; "required": true; "isSignal": true; }; "containerEl": { "alias": "containerEl"; "required": true; "isSignal": true; }; "cellRenderers": { "alias": "cellRenderers"; "required": false; "isSignal": true; }; "globalCellRenderer": { "alias": "globalCellRenderer"; "required": false; "isSignal": true; }; }, { "close": "close"; }, never, never, true, never>;
291
+ }
292
+
263
293
  /**
264
294
  * Column definition extended for Angular — allows `cellRenderer`,
265
295
  * `editRenderer`, and `headerRenderer` to be passed directly as
@@ -305,6 +335,7 @@ declare class GpGridViewModel {
305
335
  readonly selectionRange: _angular_core.WritableSignal<CellRange>;
306
336
  readonly editingCell: _angular_core.WritableSignal<EditingCellState>;
307
337
  readonly hoverPosition: _angular_core.WritableSignal<CellPosition>;
338
+ readonly peekCell: _angular_core.WritableSignal<CellPosition>;
308
339
  readonly columnsOverride: _angular_core.WritableSignal<ColumnDefinition[]>;
309
340
  readonly dragState: _angular_core.WritableSignal<DragState>;
310
341
  readonly contentWidth: _angular_core.WritableSignal<number>;
@@ -378,6 +409,12 @@ declare class GpGridComponent implements OnInit, AfterViewInit, OnDestroy {
378
409
  protected computeRowClassesFn: (rowIndex: number, rowData: unknown) => string[];
379
410
  protected computeCellClassesFn: (rowIndex: number, colIndex: number, column: ColumnDefinition, rowData: unknown) => string[];
380
411
  protected onCellDoubleClick(evt: CellDoubleClickEvent): void;
412
+ protected onPeekClose(): void;
413
+ protected peekContext: _angular_core.Signal<{
414
+ peek: _gp_grid_core.CellPosition;
415
+ column: ColumnDefinition;
416
+ rowData: unknown;
417
+ }>;
381
418
  protected onEditValueChange(value: string): void;
382
419
  protected onEditCommit(): void;
383
420
  protected onEditCancel(): void;
@@ -521,5 +558,5 @@ declare const injectGridData: <TData>() => GridDataService<TData>;
521
558
  */
522
559
  declare const provideGridData: <TData>(options: GridDataOptions<TData>) => Provider[];
523
560
 
524
- export { FilterPopupComponent, GRID_DATA_OPTIONS, GpGridComponent, GridBodyComponent, GridDataService, GridHeaderComponent, GridOverlaysComponent, createGridData, injectGridData, provideGridData };
561
+ export { CellPeekComponent, FilterPopupComponent, GRID_DATA_OPTIONS, GpGridComponent, GridBodyComponent, GridDataService, GridHeaderComponent, GridOverlaysComponent, createGridData, injectGridData, provideGridData };
525
562
  export type { ActiveFilterPopup, AngularColumnDefinition, CellClassFn, CellDoubleClickEvent, CellPointerDownEvent, CellPointerEnterEvent, CellRendererTemplate, CreateGridDataOptions, EditRendererTemplate, EditingCellState, FillHandlePointerDownEvent, FilterPointerDownEvent, GridDataApi, GridDataOptions, HeaderPointerDownEvent, HeaderRendererTemplate, HeaderSortEvent, ResizePointerDownEvent, RowClassFn };