@gp-grid/angular 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/styles.css CHANGED
@@ -614,7 +614,8 @@
614
614
  display: flex;
615
615
  flex-direction: column;
616
616
  gap: 10px;
617
- overflow: hidden;
617
+ overflow-y: auto;
618
+ min-height: 0;
618
619
  }
619
620
 
620
621
  /* Mode toggle (Values / Condition) */
@@ -823,18 +823,31 @@ class FilterPopupComponent {
823
823
  this.anchorEl();
824
824
  this.currentFilter();
825
825
  this.initFromCurrentFilter();
826
- requestAnimationFrame(() => this.updatePosition());
826
+ // Update synchronously so the new column's anchor lands before paint,
827
+ // not one frame later (which would briefly show the popup at the
828
+ // previously-open column's position).
829
+ this.updatePosition();
827
830
  });
828
831
  }
829
832
  ngAfterViewInit() {
833
+ // Run once the popup element exists; the constructor effect may have run
834
+ // before the view was ready and bailed.
835
+ this.updatePosition();
830
836
  requestAnimationFrame(() => {
831
837
  document.addEventListener('pointerdown', this.onDocumentPointerDown, true);
832
838
  });
833
- window.addEventListener('resize', this.onWindowResize);
839
+ // Scroll events don't bubble, so listen in the capture phase on window to
840
+ // catch scrolls from the grid body, the page, and any wrapping scroll
841
+ // container in the host app.
842
+ window.addEventListener('scroll', this.onWindowScrollOrResize, { passive: true, capture: true });
843
+ window.addEventListener('resize', this.onWindowScrollOrResize);
834
844
  }
835
845
  ngOnDestroy() {
836
846
  document.removeEventListener('pointerdown', this.onDocumentPointerDown, true);
837
- window.removeEventListener('resize', this.onWindowResize);
847
+ window.removeEventListener('scroll', this.onWindowScrollOrResize, { capture: true });
848
+ window.removeEventListener('resize', this.onWindowScrollOrResize);
849
+ if (this.repositionRafId !== null)
850
+ cancelAnimationFrame(this.repositionRafId);
838
851
  }
839
852
  onEscape() {
840
853
  this.close.emit();
@@ -947,8 +960,14 @@ class FilterPopupComponent {
947
960
  return;
948
961
  this.close.emit();
949
962
  };
950
- onWindowResize = () => {
951
- this.updatePosition();
963
+ repositionRafId = null;
964
+ onWindowScrollOrResize = () => {
965
+ if (this.repositionRafId !== null)
966
+ return;
967
+ this.repositionRafId = requestAnimationFrame(() => {
968
+ this.repositionRafId = null;
969
+ this.updatePosition();
970
+ });
952
971
  };
953
972
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: FilterPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
954
973
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: FilterPopupComponent, isStandalone: true, selector: "gp-grid-filter-popup", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, colIndex: { classPropertyName: "colIndex", publicName: "colIndex", isSignal: true, isRequired: true, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: true, transformFunction: null }, distinctValues: { classPropertyName: "distinctValues", publicName: "distinctValues", isSignal: true, isRequired: true, transformFunction: null }, currentFilter: { classPropertyName: "currentFilter", publicName: "currentFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply", close: "close" }, host: { listeners: { "keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "popupEl", first: true, predicate: ["popupEl"], descendants: true }], ngImport: i0, template: "\n<div\n #popupEl\n class=\"gp-grid-filter-popup\"\n [style.position]=\"'fixed'\"\n [style.zIndex]=\"10000\"\n [style.top.px]=\"popupTop()\"\n [style.left.px]=\"popupLeft()\"\n [style.minWidth.px]=\"popupMinWidth()\"\n [style.visibility]=\"positioned() ? 'visible' : 'hidden'\"\n (keydown.escape)=\"close.emit()\"\n (click)=\"$event.stopPropagation()\">\n\n <div class=\"gp-grid-filter-header\">\n Filter: {{ column().headerName ?? column().field }}\n </div>\n\n <div [class]=\"'gp-grid-filter-content ' + (isNumberColumn() ? 'gp-grid-filter-number' : 'gp-grid-filter-text')\">\n @if (isNumberColumn()) {\n @for (cond of numberConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setNumberNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setNumberNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onNumberOperatorChange(i, $any($event.target).value)\">\n @for (op of numberOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessNumberOp(cond.operator)) {\n <input\n type=\"number\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n @if (cond.operator === 'between') {\n <span class=\"gp-grid-filter-to\">to</span>\n <input\n type=\"number\"\n [value]=\"cond.valueTo\"\n (input)=\"cond.valueTo = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n }\n @if (numberConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeNumberCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addNumberCondition()\">\n + Add condition\n </button>\n } @else {\n @if (showValuesMode()) {\n <div class=\"gp-grid-filter-mode-toggle\">\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'values'\"\n (click)=\"filterMode = 'values'\">\n Values\n </button>\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'condition'\"\n (click)=\"filterMode = 'condition'\">\n Condition\n </button>\n </div>\n }\n\n @if (filterMode === 'values' && showValuesMode()) {\n <input\n class=\"gp-grid-filter-search\"\n type=\"text\"\n [value]=\"searchText\"\n (input)=\"searchText = $any($event.target).value\"\n placeholder=\"Search...\" />\n <div class=\"gp-grid-filter-actions\">\n <button type=\"button\" (click)=\"selectAll()\">Select All</button>\n <button type=\"button\" (click)=\"deselectAll()\">Deselect All</button>\n </div>\n <div class=\"gp-grid-filter-list\">\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"includeBlanks\"\n (change)=\"includeBlanks = $any($event.target).checked\" />\n <span class=\"gp-grid-filter-blank\">(Blanks)</span>\n </label>\n @for (entry of filteredUniqueEntries(); track entry.key) {\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"selectedValues.has(entry.key)\"\n (change)=\"toggleValue(entry.key, $any($event.target).checked)\" />\n <span>{{ entry.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (filterMode === 'condition') {\n @for (cond of textConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setTextNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setTextNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onTextOperatorChange(i, $any($event.target).value)\">\n @for (op of textOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessTextOp(cond.operator)) {\n <input\n class=\"gp-grid-filter-text-input\"\n type=\"text\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n @if (textConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeTextCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addTextCondition()\">\n + Add condition\n </button>\n }\n }\n\n <div class=\"gp-grid-filter-buttons\">\n <button type=\"button\" class=\"gp-grid-filter-btn-clear\" (click)=\"handleClear()\">\n Clear\n </button>\n <button type=\"button\" class=\"gp-grid-filter-btn-apply\" (click)=\"handleApply()\">\n Apply\n </button>\n </div>\n </div>\n</div>\n", isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
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.15.0",
4
+ "version": "0.16.1",
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.15.0",
54
+ "@gp-grid/core": "0.16.1",
55
55
  "tslib": "^2.8.1"
56
56
  },
57
57
  "sideEffects": false,
@@ -219,7 +219,8 @@ declare class FilterPopupComponent implements AfterViewInit, OnDestroy {
219
219
  private initFromCurrentFilter;
220
220
  private updatePosition;
221
221
  private onDocumentPointerDown;
222
- private onWindowResize;
222
+ private repositionRafId;
223
+ private onWindowScrollOrResize;
223
224
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FilterPopupComponent, never>;
224
225
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<FilterPopupComponent, "gp-grid-filter-popup", never, { "column": { "alias": "column"; "required": true; "isSignal": true; }; "colIndex": { "alias": "colIndex"; "required": true; "isSignal": true; }; "anchorEl": { "alias": "anchorEl"; "required": true; "isSignal": true; }; "distinctValues": { "alias": "distinctValues"; "required": true; "isSignal": true; }; "currentFilter": { "alias": "currentFilter"; "required": false; "isSignal": true; }; }, { "apply": "apply"; "close": "close"; }, never, never, true, never>;
225
226
  }