@alaarab/ogrid-angular-material 2.1.3 → 2.1.5

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,4 +1,7 @@
1
- export * from '@alaarab/ogrid-angular';
1
+ export type { ColumnFilterType, IDateFilterValue, IColumnFilterDef, IColumnMeta, IValueParserParams, ICellValueChangedEvent, ICellEditorProps, CellEditorParams, HeaderCell, HeaderRow, RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IVirtualScrollConfig, IColumnReorderConfig, IOGridApi, CsvColumn, StatusBarPart, StatusBarPartsInput, PaginationViewModel, GridContextMenuItem, IColumnHeaderMenuItem, GridContextMenuHandlerProps, ColumnHeaderMenuInput, ColumnHeaderMenuHandlers, ParseValueResult, AggregationResult, GridRowComparatorProps, ColumnPinState, IDropTarget, ICalculateDropTargetParams, IVisibleRange, HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, OverlayRect, ISortState, ArrowNavigationContext, ArrowNavigationResult, ZIndexKey, } from '@alaarab/ogrid-angular';
2
+ export { toUserLike, isInSelectionRange, normalizeSelectionRange, escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, isFilterConfig, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, GRID_CONTEXT_MENU_ITEMS, COLUMN_HEADER_MENU_ITEMS, getContextMenuHandlers, getColumnHeaderMenuItems, formatShortcut, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, areGridRowPropsEqual, isRowInRange, getPinStateForColumn, reorderColumnArray, calculateDropTarget, computeVisibleRange, computeTotalHeight, getScrollTopForRow, getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, debounce, measureRange, injectGlobalStyles, computeNextSortState, measureColumnContentWidth, AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, findCtrlArrowTarget, computeTabNavigation, computeArrowNavigation, applyCellDeletion, rangesEqual, clampSelectionToBounds, computeAutoScrollSpeed, applyRangeRowSelection, computeRowSelectionState, formatCellValueForTsv, formatSelectionAsTsv, parseTsvClipboard, applyPastedValues, applyCutClear, applyFillValues, UndoRedoStack, validateColumns, validateRowIds, CHECKBOX_COLUMN_WIDTH, ROW_NUMBER_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, GRID_BORDER_RADIUS, DEFAULT_DEBOUNCE_MS, PEOPLE_SEARCH_DEBOUNCE_MS, SIDEBAR_TRANSITION_MS, Z_INDEX, } from '@alaarab/ogrid-angular';
3
+ export type { IColumnDef, IColumnGroupDef, IColumnDefinition, IOGridProps, IOGridClientProps, IOGridServerProps, IOGridDataGridProps, ColumnChooserPlacement, OGridPagination, OGridColumnChooser, OGridFilters, OGridSideBarState, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, DataGridStateResult, SideBarProps, SideBarFilterColumn, IColumnHeaderFilterProps, IColumnChooserProps, } from '@alaarab/ogrid-angular';
4
+ export { OGridService, DataGridStateService, DataGridLayoutHelper, DataGridEditingHelper, DataGridInteractionHelper, ColumnReorderService, VirtualScrollService, OGridLayoutComponent, StatusBarComponent, GridContextMenuComponent, SideBarComponent, MarchingAntsOverlayComponent, EmptyStateComponent, BaseOGridComponent, BaseDataGridTableComponent, BaseColumnHeaderFilterComponent, BaseColumnChooserComponent, BasePaginationControlsComponent, BaseInlineCellEditorComponent, INLINE_CELL_EDITOR_TEMPLATE, INLINE_CELL_EDITOR_STYLES, BasePopoverCellEditorComponent, POPOVER_CELL_EDITOR_TEMPLATE, POPOVER_CELL_EDITOR_OVERLAY_STYLES, OGRID_THEME_VARS_CSS, createDebouncedSignal, createDebouncedCallback, createLatestCallback, } from '@alaarab/ogrid-angular';
2
5
  export { OGridComponent } from './ogrid/ogrid.component';
3
6
  export { DataGridTableComponent } from './datagrid-table/datagrid-table.component';
4
7
  export { ColumnHeaderFilterComponent } from './column-header-filter/column-header-filter.component';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-angular-material",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
4
4
  "description": "OGrid Angular Material – MatTable-based data grid with sorting, filtering, pagination, column chooser, and CSV export.",
5
5
  "main": "dist/esm/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -9,11 +9,11 @@
9
9
  ".": {
10
10
  "types": "./dist/types/index.d.ts",
11
11
  "import": "./dist/esm/index.js",
12
- "require": "./dist/esm/index.js"
12
+ "default": "./dist/esm/index.js"
13
13
  }
14
14
  },
15
15
  "scripts": {
16
- "build": "rimraf dist && tsc -p tsconfig.build.json",
16
+ "build": "rimraf dist && tsup && tsc -p tsconfig.build.json",
17
17
  "test": "jest --passWithNoTests",
18
18
  "storybook": "ng run angular-material:storybook",
19
19
  "build-storybook": "ng run angular-material:build-storybook"
@@ -37,7 +37,7 @@
37
37
  "node": ">=18"
38
38
  },
39
39
  "dependencies": {
40
- "@alaarab/ogrid-angular": "2.1.3"
40
+ "@alaarab/ogrid-angular": "2.1.5"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@angular/cdk": "^21.0.0",
@@ -1,121 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { Component, ChangeDetectionStrategy } from '@angular/core';
8
- import { BaseColumnChooserComponent } from '@alaarab/ogrid-angular';
9
- /**
10
- * Column visibility chooser dropdown using Angular Material styling.
11
- * Standalone component with inline template.
12
- */
13
- let ColumnChooserComponent = class ColumnChooserComponent extends BaseColumnChooserComponent {
14
- onDocumentClick(event) {
15
- const el = event.target;
16
- if (!el.closest('ogrid-column-chooser')) {
17
- this.isOpen.set(false);
18
- }
19
- }
20
- };
21
- ColumnChooserComponent = __decorate([
22
- Component({
23
- selector: 'ogrid-column-chooser',
24
- standalone: true,
25
- changeDetection: ChangeDetectionStrategy.OnPush,
26
- template: `
27
- <div class="ogrid-column-chooser">
28
- <button
29
- class="ogrid-column-chooser__trigger"
30
- (click)="toggle()"
31
- [attr.aria-expanded]="isOpen()"
32
- aria-haspopup="listbox"
33
- >
34
- &#9638; Column Visibility ({{ visibleCount() }} of {{ totalCount() }})
35
- <span class="ogrid-column-chooser__caret">{{ isOpen() ? '&#9650;' : '&#9660;' }}</span>
36
- </button>
37
-
38
- @if (isOpen()) {
39
- <div class="ogrid-column-chooser__dropdown" (click)="$event.stopPropagation()">
40
- <div class="ogrid-column-chooser__header">
41
- Select Columns ({{ visibleCount() }} of {{ totalCount() }})
42
- </div>
43
-
44
- <div class="ogrid-column-chooser__list">
45
- @for (col of columns; track col.columnId) {
46
- <label class="ogrid-column-chooser__item">
47
- <input
48
- type="checkbox"
49
- [checked]="visibleColumns.has(col.columnId)"
50
- (change)="onCheckboxChange(col.columnId, $event)"
51
- />
52
- <span>{{ col.name }}</span>
53
- </label>
54
- }
55
- </div>
56
-
57
- <div class="ogrid-column-chooser__footer">
58
- <button class="ogrid-column-chooser__btn" (click)="onClearAll()">Clear All</button>
59
- <button class="ogrid-column-chooser__btn ogrid-column-chooser__btn--primary" (click)="selectAll()">Select All</button>
60
- </div>
61
- </div>
62
- }
63
- </div>
64
- `,
65
- styles: [`
66
- :host { display: inline-flex; position: relative; }
67
- .ogrid-column-chooser { position: relative; }
68
- .ogrid-column-chooser__trigger {
69
- display: inline-flex; align-items: center; gap: 6px;
70
- padding: 6px 12px; border: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.23)); border-radius: 4px;
71
- background: transparent; cursor: pointer; font-size: 14px; font-weight: 600;
72
- text-transform: none; white-space: nowrap;
73
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
74
- }
75
- .ogrid-column-chooser__trigger:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.04)); }
76
- .ogrid-column-chooser__caret { font-size: 10px; }
77
- .ogrid-column-chooser__dropdown {
78
- position: absolute; top: 100%; right: 0; z-index: 1000;
79
- min-width: 220px; margin-top: 4px;
80
- background: var(--ogrid-bg, #ffffff); border: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); border-radius: 4px;
81
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
82
- }
83
- .ogrid-column-chooser__header {
84
- padding: 8px 12px; font-size: 14px; font-weight: 600;
85
- border-bottom: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
86
- background: var(--ogrid-header-bg, rgba(0, 0, 0, 0.04));
87
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
88
- }
89
- .ogrid-column-chooser__list {
90
- max-height: 320px; overflow-y: auto; padding: 4px 0;
91
- }
92
- .ogrid-column-chooser__item {
93
- display: flex; align-items: center; gap: 8px;
94
- padding: 4px 12px; min-height: 32px; cursor: pointer; font-size: 14px;
95
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
96
- }
97
- .ogrid-column-chooser__item:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.04)); }
98
- .ogrid-column-chooser__footer {
99
- display: flex; justify-content: flex-end; gap: 8px;
100
- padding: 8px 12px; border-top: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
101
- background: var(--ogrid-header-bg, rgba(0, 0, 0, 0.04));
102
- }
103
- .ogrid-column-chooser__btn {
104
- padding: 4px 12px; border: none; border-radius: 4px;
105
- background: transparent; cursor: pointer; font-size: 13px; text-transform: none;
106
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
107
- }
108
- .ogrid-column-chooser__btn:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.04)); }
109
- .ogrid-column-chooser__btn--primary {
110
- background: var(--mat-sys-primary, #1976d2); color: #fff;
111
- }
112
- .ogrid-column-chooser__btn--primary:hover {
113
- opacity: 0.9;
114
- }
115
- `],
116
- host: {
117
- '(document:click)': 'onDocumentClick($event)',
118
- },
119
- })
120
- ], ColumnChooserComponent);
121
- export { ColumnChooserComponent };
@@ -1,325 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { Component, ChangeDetectionStrategy, ViewChild } from '@angular/core';
8
- import { BaseColumnHeaderFilterComponent } from '@alaarab/ogrid-angular';
9
- /**
10
- * Column header filter component with sort + filter icon + popover.
11
- * Standalone component with inline template.
12
- */
13
- let ColumnHeaderFilterComponent = class ColumnHeaderFilterComponent extends BaseColumnHeaderFilterComponent {
14
- getHeaderEl() {
15
- return this.headerEl;
16
- }
17
- onDocumentClickWrapper(event) {
18
- this.onDocumentClick(event, 'ogrid-column-header-filter');
19
- }
20
- };
21
- __decorate([
22
- ViewChild('headerEl')
23
- ], ColumnHeaderFilterComponent.prototype, "headerEl", void 0);
24
- ColumnHeaderFilterComponent = __decorate([
25
- Component({
26
- selector: 'ogrid-column-header-filter',
27
- standalone: true,
28
- changeDetection: ChangeDetectionStrategy.OnPush,
29
- template: `
30
- <div class="ogrid-header-filter" #headerEl>
31
- <div class="ogrid-header-filter__label">
32
- <span class="ogrid-header-filter__name" [title]="columnName" data-header-label>
33
- {{ columnName }}
34
- </span>
35
- </div>
36
-
37
- <div class="ogrid-header-filter__actions">
38
- @if (filterType !== 'none') {
39
- <button
40
- class="ogrid-header-filter__filter-btn"
41
- [class.ogrid-header-filter__filter-btn--active]="hasActiveFilter() || isFilterOpen()"
42
- (click)="toggleFilter($event)"
43
- [attr.aria-label]="'Filter ' + columnName"
44
- [title]="'Filter ' + columnName"
45
- >
46
- <span class="ogrid-header-filter__funnel"></span>
47
- @if (hasActiveFilter()) {
48
- <span class="ogrid-header-filter__dot"></span>
49
- }
50
- </button>
51
- }
52
- </div>
53
- </div>
54
-
55
- @if (isFilterOpen() && filterType !== 'none') {
56
- <div
57
- class="ogrid-header-filter__popover"
58
- [style.top.px]="popoverTop()"
59
- [style.left.px]="popoverLeft()"
60
- (click)="$event.stopPropagation()"
61
- >
62
- <div class="ogrid-header-filter__popover-header">
63
- Filter: {{ columnName }}
64
- </div>
65
-
66
- @switch (filterType) {
67
- @case ('text') {
68
- <div class="ogrid-header-filter__popover-body" style="width: 260px;">
69
- <div style="padding: 12px;">
70
- <input
71
- type="text"
72
- class="ogrid-header-filter__input"
73
- placeholder="Enter search term..."
74
- [value]="tempTextValue()"
75
- (input)="tempTextValue.set(asInputValue($event))"
76
- (keydown)="onTextKeydown($event)"
77
- autocomplete="off"
78
- />
79
- </div>
80
- <div class="ogrid-header-filter__popover-actions">
81
- <button class="ogrid-header-filter__action-btn" [disabled]="!tempTextValue()" (click)="handleTextClear()">Clear</button>
82
- <button class="ogrid-header-filter__action-btn ogrid-header-filter__action-btn--primary" (click)="handleTextApply()">Apply</button>
83
- </div>
84
- </div>
85
- }
86
- @case ('multiSelect') {
87
- <div class="ogrid-header-filter__popover-body" style="width: 280px;">
88
- <div style="padding: 12px 12px 4px;">
89
- <input
90
- type="text"
91
- class="ogrid-header-filter__input"
92
- placeholder="Search..."
93
- [value]="searchText()"
94
- (input)="searchText.set(asInputValue($event))"
95
- (keydown)="$event.stopPropagation()"
96
- autocomplete="off"
97
- />
98
- <div class="ogrid-header-filter__options-info">
99
- {{ filteredOptions().length }} of {{ (options ?? []).length }} options
100
- </div>
101
- </div>
102
- <div class="ogrid-header-filter__select-actions">
103
- <button class="ogrid-header-filter__action-btn" (click)="handleSelectAllFiltered()">
104
- Select All ({{ filteredOptions().length }})
105
- </button>
106
- <button class="ogrid-header-filter__action-btn" (click)="handleClearSelection()">Clear</button>
107
- </div>
108
- <div class="ogrid-header-filter__options-list">
109
- @if (isLoadingOptions) {
110
- <div class="ogrid-header-filter__loading">Loading...</div>
111
- } @else if (filteredOptions().length === 0) {
112
- <div class="ogrid-header-filter__empty">No options found</div>
113
- } @else {
114
- @for (option of filteredOptions(); track option) {
115
- <label class="ogrid-header-filter__option">
116
- <input
117
- type="checkbox"
118
- [checked]="tempSelected().has(option)"
119
- (change)="handleCheckboxChange(option, $event)"
120
- />
121
- <span>{{ option }}</span>
122
- </label>
123
- }
124
- }
125
- </div>
126
- <div class="ogrid-header-filter__popover-actions" style="border-top: 1px solid rgba(0,0,0,0.12);">
127
- <button class="ogrid-header-filter__action-btn" (click)="handleClearSelection()">Clear</button>
128
- <button class="ogrid-header-filter__action-btn ogrid-header-filter__action-btn--primary" (click)="handleApplyMultiSelect()">Apply</button>
129
- </div>
130
- </div>
131
- }
132
- @case ('people') {
133
- <div class="ogrid-header-filter__popover-body" style="width: 300px;">
134
- @if (selectedUser) {
135
- <div class="ogrid-header-filter__people-selected">
136
- <div class="ogrid-header-filter__people-info-label">Currently filtered by:</div>
137
- <div class="ogrid-header-filter__people-card">
138
- <div class="ogrid-header-filter__people-avatar">{{ selectedUser!.displayName?.[0] ?? '?' }}</div>
139
- <div class="ogrid-header-filter__people-details">
140
- <div>{{ selectedUser!.displayName }}</div>
141
- <div class="ogrid-header-filter__people-email">{{ selectedUser!.email }}</div>
142
- </div>
143
- <button class="ogrid-header-filter__btn" (click)="handleClearUser()" aria-label="Remove filter">&times;</button>
144
- </div>
145
- </div>
146
- }
147
- <div style="padding: 12px 12px 4px;">
148
- <input
149
- type="text"
150
- class="ogrid-header-filter__input"
151
- placeholder="Search for a person..."
152
- [value]="peopleSearchText()"
153
- (input)="onPeopleSearchInput($event)"
154
- (keydown)="$event.stopPropagation()"
155
- autocomplete="off"
156
- />
157
- </div>
158
- <div class="ogrid-header-filter__options-list">
159
- @if (isPeopleLoading() && peopleSearchText().trim()) {
160
- <div class="ogrid-header-filter__loading">Loading...</div>
161
- } @else if (peopleSuggestions().length === 0 && peopleSearchText().trim()) {
162
- <div class="ogrid-header-filter__empty">No results found</div>
163
- } @else if (peopleSearchText().trim()) {
164
- @for (user of peopleSuggestions(); track user.id || user.email || user.displayName) {
165
- <div class="ogrid-header-filter__people-option" (click)="handleUserSelect(user)">
166
- <div class="ogrid-header-filter__people-avatar">{{ user.displayName?.[0] ?? '?' }}</div>
167
- <div class="ogrid-header-filter__people-details">
168
- <div>{{ user.displayName }}</div>
169
- <div class="ogrid-header-filter__people-email">{{ user.email }}</div>
170
- </div>
171
- </div>
172
- }
173
- } @else {
174
- <div class="ogrid-header-filter__empty">Type to search...</div>
175
- }
176
- </div>
177
- @if (selectedUser) {
178
- <div style="padding: 8px 12px; border-top: 1px solid rgba(0,0,0,0.12);">
179
- <button class="ogrid-header-filter__action-btn" style="width: 100%;" (click)="handleClearUser()">Clear Filter</button>
180
- </div>
181
- }
182
- </div>
183
- }
184
- @case ('date') {
185
- <div class="ogrid-header-filter__popover-body" style="padding: 12px; display: flex; flex-direction: column; gap: 8px;">
186
- <div style="display: flex; align-items: center; gap: 8px;">
187
- <span style="min-width: 36px; font-size: 12px;">From:</span>
188
- <input type="date" [value]="tempDateFrom()" (input)="tempDateFrom.set(asInputValue($event))" style="flex: 1; padding: 4px 6px;" />
189
- </div>
190
- <div style="display: flex; align-items: center; gap: 8px;">
191
- <span style="min-width: 36px; font-size: 12px;">To:</span>
192
- <input type="date" [value]="tempDateTo()" (input)="tempDateTo.set(asInputValue($event))" style="flex: 1; padding: 4px 6px;" />
193
- </div>
194
- <div class="ogrid-header-filter__popover-actions" style="margin-top: 4px;">
195
- <button class="ogrid-header-filter__action-btn" [disabled]="!tempDateFrom() && !tempDateTo()" (click)="handleDateClear()">Clear</button>
196
- <button class="ogrid-header-filter__action-btn ogrid-header-filter__action-btn--primary" (click)="handleDateApply()">Apply</button>
197
- </div>
198
- </div>
199
- }
200
- }
201
- </div>
202
- }
203
- `,
204
- styles: [`
205
- :host { display: flex; align-items: center; flex: 1; min-width: 0; position: relative; }
206
- .ogrid-header-filter { display: flex; align-items: center; width: 100%; min-width: 0; }
207
- .ogrid-header-filter__label { flex: 1; min-width: 0; overflow: hidden; }
208
- .ogrid-header-filter__name {
209
- display: block; font-weight: 600; font-size: 14px; line-height: 1.4;
210
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
211
- }
212
- .ogrid-header-filter__actions { display: flex; align-items: center; margin-left: 4px; flex-shrink: 0; }
213
- .ogrid-header-filter__btn {
214
- width: 24px; height: 24px; padding: 2px; border: none; border-radius: 4px;
215
- background: transparent; cursor: pointer; font-size: 12px; line-height: 1;
216
- display: inline-flex; align-items: center; justify-content: center; position: relative;
217
- color: var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.54));
218
- }
219
- .ogrid-header-filter__btn:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.08)); }
220
- .ogrid-header-filter__btn--active { color: var(--mat-sys-primary, #1976d2); }
221
- .ogrid-header-filter__filter-btn {
222
- width: 24px; height: 24px; padding: 2px; border: none; border-radius: 4px;
223
- background: transparent; cursor: pointer; line-height: 1;
224
- display: inline-flex; align-items: center; justify-content: center; position: relative;
225
- opacity: 0.6; transition: opacity 0.15s;
226
- }
227
- .ogrid-header-filter:hover .ogrid-header-filter__filter-btn { opacity: 0.8; }
228
- .ogrid-header-filter__filter-btn:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.08)); opacity: 1 !important; }
229
- .ogrid-header-filter__filter-btn--active { opacity: 1 !important; }
230
- .ogrid-header-filter__funnel {
231
- display: block; width: 0; height: 0;
232
- border-left: 5px solid transparent; border-right: 5px solid transparent;
233
- border-top: 6px solid var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.65));
234
- position: relative;
235
- }
236
- .ogrid-header-filter__funnel::after {
237
- content: ''; display: block; width: 2px; height: 4px;
238
- background: var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.65)); position: absolute;
239
- top: -1px; left: -1px;
240
- }
241
- .ogrid-header-filter__filter-btn--active .ogrid-header-filter__funnel {
242
- border-top-color: var(--mat-sys-primary, #1976d2);
243
- }
244
- .ogrid-header-filter__filter-btn--active .ogrid-header-filter__funnel::after {
245
- background: var(--mat-sys-primary, #1976d2);
246
- }
247
- .ogrid-header-filter__dot {
248
- position: absolute; top: 2px; right: 2px;
249
- width: 6px; height: 6px; border-radius: 50%;
250
- background: var(--mat-sys-primary, #1976d2);
251
- }
252
- .ogrid-header-filter__popover {
253
- position: fixed; z-index: 1000;
254
- background: var(--ogrid-bg, #ffffff); border: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.2));
255
- border-radius: 8px; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2), 0 1px 4px rgba(0, 0, 0, 0.1);
256
- margin-top: 4px; color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
257
- }
258
- .ogrid-header-filter__popover-header {
259
- padding: 8px 12px; font-size: 14px; font-weight: 600;
260
- border-bottom: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
261
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
262
- }
263
- .ogrid-header-filter__popover-body { }
264
- .ogrid-header-filter__popover-actions {
265
- display: flex; justify-content: flex-end; gap: 8px; padding: 8px 12px;
266
- }
267
- .ogrid-header-filter__input {
268
- width: 100%; padding: 8px 12px; border: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.23));
269
- border-radius: 4px; font-size: 14px; box-sizing: border-box;
270
- background: var(--ogrid-bg, #ffffff); color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
271
- }
272
- .ogrid-header-filter__input:focus { outline: 2px solid var(--mat-sys-primary, #1976d2); outline-offset: -1px; }
273
- .ogrid-header-filter__options-info { margin-top: 4px; font-size: 12px; color: var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.6)); }
274
- .ogrid-header-filter__select-actions {
275
- display: flex; justify-content: space-between; padding: 4px 12px;
276
- }
277
- .ogrid-header-filter__options-list { max-height: 240px; overflow-y: auto; padding: 0 4px; }
278
- .ogrid-header-filter__option {
279
- display: flex; align-items: center; gap: 8px;
280
- padding: 4px 8px; cursor: pointer; font-size: 14px;
281
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
282
- }
283
- .ogrid-header-filter__option:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.04)); }
284
- .ogrid-header-filter__loading, .ogrid-header-filter__empty {
285
- padding: 16px; text-align: center; font-size: 14px; color: var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.6));
286
- }
287
- .ogrid-header-filter__action-btn {
288
- padding: 4px 12px; border: none; border-radius: 4px;
289
- background: transparent; cursor: pointer; font-size: 13px;
290
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
291
- }
292
- .ogrid-header-filter__action-btn:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.04)); }
293
- .ogrid-header-filter__action-btn:disabled { opacity: 0.38; cursor: default; }
294
- .ogrid-header-filter__action-btn--primary {
295
- background: var(--mat-sys-primary, #1976d2); color: #fff;
296
- }
297
- .ogrid-header-filter__action-btn--primary:hover { opacity: 0.9; }
298
- .ogrid-header-filter__people-selected {
299
- padding: 12px; border-bottom: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
300
- }
301
- .ogrid-header-filter__people-info-label { font-size: 12px; color: var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.6)); }
302
- .ogrid-header-filter__people-card {
303
- display: flex; align-items: center; gap: 8px; margin-top: 4px;
304
- }
305
- .ogrid-header-filter__people-avatar {
306
- width: 32px; height: 32px; border-radius: 50%; background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.08));
307
- display: flex; align-items: center; justify-content: center;
308
- font-size: 14px; font-weight: 600; flex-shrink: 0;
309
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
310
- }
311
- .ogrid-header-filter__people-details { flex: 1; min-width: 0; font-size: 14px; color: var(--ogrid-fg, rgba(0, 0, 0, 0.87)); }
312
- .ogrid-header-filter__people-details > div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
313
- .ogrid-header-filter__people-email { font-size: 12px; color: var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.6)); }
314
- .ogrid-header-filter__people-option {
315
- display: flex; align-items: center; gap: 8px; padding: 8px 12px; cursor: pointer;
316
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
317
- }
318
- .ogrid-header-filter__people-option:hover { background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.04)); }
319
- `],
320
- host: {
321
- '(document:click)': 'onDocumentClickWrapper($event)',
322
- },
323
- })
324
- ], ColumnHeaderFilterComponent);
325
- export { ColumnHeaderFilterComponent };
@@ -1,144 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { Component, ChangeDetectionStrategy, ViewChild, computed, Input, signal } from '@angular/core';
8
- import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
9
- import { MatDividerModule } from '@angular/material/divider';
10
- import { getColumnHeaderMenuItems } from '@alaarab/ogrid-angular';
11
- /**
12
- * Column header dropdown menu for pin/unpin, sort, and autosize actions.
13
- * Uses Angular Material MatMenu.
14
- *
15
- * Uses signal-backed @Input setters so that computed() tracks changes
16
- * (plain @Input properties are not reactive in Angular signals).
17
- */
18
- let ColumnHeaderMenuComponent = class ColumnHeaderMenuComponent {
19
- constructor() {
20
- // Signal-backed inputs so computed() tracks changes reactively
21
- this._canPinLeft = signal(true);
22
- this._canPinRight = signal(true);
23
- this._canUnpin = signal(false);
24
- this._currentSort = signal(null);
25
- this._isSortable = signal(true);
26
- this._isResizable = signal(true);
27
- this.handlers = {};
28
- this.menuItems = computed(() => getColumnHeaderMenuItems({
29
- canPinLeft: this._canPinLeft(),
30
- canPinRight: this._canPinRight(),
31
- canUnpin: this._canUnpin(),
32
- currentSort: this._currentSort(),
33
- isSortable: this._isSortable(),
34
- isResizable: this._isResizable(),
35
- }));
36
- }
37
- set canPinLeft(v) { this._canPinLeft.set(v); }
38
- set canPinRight(v) { this._canPinRight.set(v); }
39
- set canUnpin(v) { this._canUnpin.set(v); }
40
- set currentSort(v) { this._currentSort.set(v); }
41
- set isSortable(v) { this._isSortable.set(v); }
42
- set isResizable(v) { this._isResizable.set(v); }
43
- handleMenuItemClick(itemId) {
44
- const h = this.handlers;
45
- const actionMap = {
46
- pinLeft: h.onPinLeft,
47
- pinRight: h.onPinRight,
48
- unpin: h.onUnpin,
49
- sortAsc: h.onSortAsc,
50
- sortDesc: h.onSortDesc,
51
- clearSort: h.onClearSort,
52
- autosizeThis: h.onAutosizeThis,
53
- autosizeAll: h.onAutosizeAll,
54
- };
55
- const action = actionMap[itemId];
56
- if (action) {
57
- action();
58
- h.onClose?.();
59
- }
60
- }
61
- };
62
- __decorate([
63
- Input({ required: true })
64
- ], ColumnHeaderMenuComponent.prototype, "columnId", void 0);
65
- __decorate([
66
- Input()
67
- ], ColumnHeaderMenuComponent.prototype, "canPinLeft", null);
68
- __decorate([
69
- Input()
70
- ], ColumnHeaderMenuComponent.prototype, "canPinRight", null);
71
- __decorate([
72
- Input()
73
- ], ColumnHeaderMenuComponent.prototype, "canUnpin", null);
74
- __decorate([
75
- Input()
76
- ], ColumnHeaderMenuComponent.prototype, "currentSort", null);
77
- __decorate([
78
- Input()
79
- ], ColumnHeaderMenuComponent.prototype, "isSortable", null);
80
- __decorate([
81
- Input()
82
- ], ColumnHeaderMenuComponent.prototype, "isResizable", null);
83
- __decorate([
84
- Input()
85
- ], ColumnHeaderMenuComponent.prototype, "handlers", void 0);
86
- __decorate([
87
- ViewChild(MatMenuTrigger)
88
- ], ColumnHeaderMenuComponent.prototype, "menuTrigger", void 0);
89
- ColumnHeaderMenuComponent = __decorate([
90
- Component({
91
- selector: 'column-header-menu',
92
- standalone: true,
93
- changeDetection: ChangeDetectionStrategy.OnPush,
94
- imports: [MatMenuModule, MatDividerModule],
95
- template: `
96
- <button
97
- [matMenuTriggerFor]="menu"
98
- class="column-header-menu-trigger"
99
- [attr.aria-label]="'Column options for ' + columnId"
100
- >
101
- &#8942;
102
- </button>
103
-
104
- <mat-menu #menu="matMenu">
105
- @for (item of menuItems(); track item.id) {
106
- <button
107
- mat-menu-item
108
- [disabled]="item.disabled"
109
- (click)="handleMenuItemClick(item.id)"
110
- >
111
- {{ item.label }}
112
- </button>
113
- @if (item.divider) {
114
- <mat-divider></mat-divider>
115
- }
116
- }
117
- </mat-menu>
118
- `,
119
- styles: [`
120
- :host { flex-shrink: 0; }
121
- .column-header-menu-trigger {
122
- width: 24px;
123
- height: 24px;
124
- padding: 0;
125
- border: none;
126
- border-radius: 4px;
127
- background: transparent;
128
- cursor: pointer;
129
- font-size: 16px;
130
- line-height: 1;
131
- display: inline-flex;
132
- align-items: center;
133
- justify-content: center;
134
- color: var(--ogrid-fg-secondary, rgba(0, 0, 0, 0.54));
135
- }
136
-
137
- .column-header-menu-trigger:hover {
138
- background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.08));
139
- color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
140
- }
141
- `],
142
- })
143
- ], ColumnHeaderMenuComponent);
144
- export { ColumnHeaderMenuComponent };