@alaarab/ogrid-angular-primeng 2.0.2 → 2.0.4
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/esm/column-header-menu/column-header-menu.component.js +136 -0
- package/dist/esm/datagrid-table/datagrid-table.component.js +152 -85
- package/dist/esm/datagrid-table/inline-cell-editor.component.js +11 -3
- package/dist/esm/index.js +1 -0
- package/dist/types/column-header-menu/column-header-menu.component.d.ts +26 -0
- package/dist/types/datagrid-table/datagrid-table.component.d.ts +20 -25
- package/dist/types/datagrid-table/inline-cell-editor.component.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,136 @@
|
|
|
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, Input, Output, EventEmitter, ViewChild } from '@angular/core';
|
|
8
|
+
import { ButtonModule } from 'primeng/button';
|
|
9
|
+
import { MenuModule } from 'primeng/menu';
|
|
10
|
+
import { COLUMN_HEADER_MENU_ITEMS } from '@alaarab/ogrid-core';
|
|
11
|
+
/**
|
|
12
|
+
* Column header dropdown menu for pin/unpin actions.
|
|
13
|
+
* Uses PrimeNG Menu component.
|
|
14
|
+
*/
|
|
15
|
+
let ColumnHeaderMenuComponent = class ColumnHeaderMenuComponent {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.pinLeft = new EventEmitter();
|
|
18
|
+
this.pinRight = new EventEmitter();
|
|
19
|
+
this.unpin = new EventEmitter();
|
|
20
|
+
this._canPinLeft = true;
|
|
21
|
+
this._canPinRight = true;
|
|
22
|
+
this._canUnpin = false;
|
|
23
|
+
this.menuModel = [];
|
|
24
|
+
}
|
|
25
|
+
set canPinLeft(value) {
|
|
26
|
+
this._canPinLeft = value;
|
|
27
|
+
this.updateMenuModel();
|
|
28
|
+
}
|
|
29
|
+
set canPinRight(value) {
|
|
30
|
+
this._canPinRight = value;
|
|
31
|
+
this.updateMenuModel();
|
|
32
|
+
}
|
|
33
|
+
set canUnpin(value) {
|
|
34
|
+
this._canUnpin = value;
|
|
35
|
+
this.updateMenuModel();
|
|
36
|
+
}
|
|
37
|
+
ngOnInit() {
|
|
38
|
+
this.updateMenuModel();
|
|
39
|
+
}
|
|
40
|
+
updateMenuModel() {
|
|
41
|
+
this.menuModel = [
|
|
42
|
+
{
|
|
43
|
+
label: COLUMN_HEADER_MENU_ITEMS[0].label,
|
|
44
|
+
disabled: !this._canPinLeft,
|
|
45
|
+
command: () => this.handlePinLeft(),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: COLUMN_HEADER_MENU_ITEMS[1].label,
|
|
49
|
+
disabled: !this._canPinRight,
|
|
50
|
+
command: () => this.handlePinRight(),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
label: COLUMN_HEADER_MENU_ITEMS[2].label,
|
|
54
|
+
disabled: !this._canUnpin,
|
|
55
|
+
command: () => this.handleUnpin(),
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
handlePinLeft() {
|
|
60
|
+
if (this._canPinLeft) {
|
|
61
|
+
this.pinLeft.emit();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
handlePinRight() {
|
|
65
|
+
if (this._canPinRight) {
|
|
66
|
+
this.pinRight.emit();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
handleUnpin() {
|
|
70
|
+
if (this._canUnpin) {
|
|
71
|
+
this.unpin.emit();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
__decorate([
|
|
76
|
+
Input()
|
|
77
|
+
], ColumnHeaderMenuComponent.prototype, "columnId", void 0);
|
|
78
|
+
__decorate([
|
|
79
|
+
Input()
|
|
80
|
+
], ColumnHeaderMenuComponent.prototype, "canPinLeft", null);
|
|
81
|
+
__decorate([
|
|
82
|
+
Input()
|
|
83
|
+
], ColumnHeaderMenuComponent.prototype, "canPinRight", null);
|
|
84
|
+
__decorate([
|
|
85
|
+
Input()
|
|
86
|
+
], ColumnHeaderMenuComponent.prototype, "canUnpin", null);
|
|
87
|
+
__decorate([
|
|
88
|
+
Output()
|
|
89
|
+
], ColumnHeaderMenuComponent.prototype, "pinLeft", void 0);
|
|
90
|
+
__decorate([
|
|
91
|
+
Output()
|
|
92
|
+
], ColumnHeaderMenuComponent.prototype, "pinRight", void 0);
|
|
93
|
+
__decorate([
|
|
94
|
+
Output()
|
|
95
|
+
], ColumnHeaderMenuComponent.prototype, "unpin", void 0);
|
|
96
|
+
__decorate([
|
|
97
|
+
ViewChild('menu')
|
|
98
|
+
], ColumnHeaderMenuComponent.prototype, "menu", void 0);
|
|
99
|
+
ColumnHeaderMenuComponent = __decorate([
|
|
100
|
+
Component({
|
|
101
|
+
selector: 'column-header-menu',
|
|
102
|
+
standalone: true,
|
|
103
|
+
imports: [ButtonModule, MenuModule],
|
|
104
|
+
template: `
|
|
105
|
+
<button
|
|
106
|
+
pButton
|
|
107
|
+
type="button"
|
|
108
|
+
icon="pi pi-ellipsis-v"
|
|
109
|
+
class="p-button-text p-button-sm column-header-menu-trigger"
|
|
110
|
+
(click)="menu.toggle($event)"
|
|
111
|
+
[attr.aria-label]="'Column options for ' + columnId"
|
|
112
|
+
></button>
|
|
113
|
+
|
|
114
|
+
<p-menu
|
|
115
|
+
#menu
|
|
116
|
+
[model]="menuModel"
|
|
117
|
+
[popup]="true"
|
|
118
|
+
appendTo="body"
|
|
119
|
+
></p-menu>
|
|
120
|
+
`,
|
|
121
|
+
styles: [`
|
|
122
|
+
.column-header-menu-trigger {
|
|
123
|
+
opacity: 0;
|
|
124
|
+
transition: opacity 0.15s;
|
|
125
|
+
padding: 0.25rem;
|
|
126
|
+
min-width: auto;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
:host:hover .column-header-menu-trigger,
|
|
130
|
+
.column-header-menu-trigger:focus {
|
|
131
|
+
opacity: 1;
|
|
132
|
+
}
|
|
133
|
+
`],
|
|
134
|
+
})
|
|
135
|
+
], ColumnHeaderMenuComponent);
|
|
136
|
+
export { ColumnHeaderMenuComponent };
|
|
@@ -6,12 +6,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { Component, input, inject, signal, computed, effect, viewChild, ChangeDetectionStrategy, } from '@angular/core';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
|
-
import { DataGridStateService, StatusBarComponent, GridContextMenuComponent, MarchingAntsOverlayComponent, EmptyStateComponent, DEFAULT_MIN_COLUMN_WIDTH, buildHeaderRows, getCellValue, } from '@alaarab/ogrid-angular';
|
|
9
|
+
import { DataGridStateService, ColumnReorderService, VirtualScrollService, StatusBarComponent, GridContextMenuComponent, MarchingAntsOverlayComponent, EmptyStateComponent, DEFAULT_MIN_COLUMN_WIDTH, buildHeaderRows, getCellValue, getHeaderFilterConfig, resolveCellDisplayContent, resolveCellStyle, } from '@alaarab/ogrid-angular';
|
|
10
10
|
import { ColumnHeaderFilterComponent } from '../column-header-filter/column-header-filter.component';
|
|
11
|
+
import { ColumnHeaderMenuComponent } from '../column-header-menu/column-header-menu.component';
|
|
11
12
|
import { InlineCellEditorComponent } from './inline-cell-editor.component';
|
|
12
13
|
let DataGridTableComponent = class DataGridTableComponent {
|
|
13
14
|
constructor() {
|
|
14
15
|
this.stateService = inject(DataGridStateService);
|
|
16
|
+
this.columnReorderService = new ColumnReorderService();
|
|
17
|
+
this.virtualScrollService = new VirtualScrollService();
|
|
15
18
|
this.wrapperRef = viewChild('wrapper');
|
|
16
19
|
this.tableContainerRef = viewChild('tableContainer');
|
|
17
20
|
// Inputs mapped from IOGridDataGridProps
|
|
@@ -55,6 +58,9 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
55
58
|
this.onCellError = input(undefined);
|
|
56
59
|
this.ariaLabel = input(undefined, { alias: 'aria-label' });
|
|
57
60
|
this.ariaLabelledBy = input(undefined, { alias: 'aria-labelledby' });
|
|
61
|
+
this.showRowNumbers = input(false);
|
|
62
|
+
this.currentPage = input(1);
|
|
63
|
+
this.pageSize = input(25);
|
|
58
64
|
this.defaultMinWidth = DEFAULT_MIN_COLUMN_WIDTH;
|
|
59
65
|
this.statusBarClasses = {
|
|
60
66
|
statusBar: 'ogrid-status-bar',
|
|
@@ -69,9 +75,11 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
69
75
|
this.resizeStartWidth = 0;
|
|
70
76
|
// Last shift state for row checkbox
|
|
71
77
|
this.lastMouseShift = false;
|
|
78
|
+
this.columnSizingVersion = signal(0);
|
|
72
79
|
this.state = computed(() => this.stateService.getState());
|
|
73
80
|
this.tableContainerEl = computed(() => this.tableContainerRef()?.nativeElement ?? null);
|
|
74
81
|
this.resolvedAriaLabel = computed(() => this.ariaLabel() ?? (this.ariaLabelledBy() ? undefined : 'Data grid'));
|
|
82
|
+
this.rowNumberOffset = computed(() => this.state().layout.hasRowNumbersCol ? (this.currentPage() - 1) * this.pageSize() : 0);
|
|
75
83
|
this.headerRows = computed(() => buildHeaderRows(this.columns(), this.visibleColumns()));
|
|
76
84
|
this.allowOverflowX = computed(() => {
|
|
77
85
|
const s = this.state();
|
|
@@ -113,6 +121,19 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
113
121
|
effect(() => {
|
|
114
122
|
const el = this.wrapperRef()?.nativeElement ?? null;
|
|
115
123
|
this.stateService.wrapperEl.set(el);
|
|
124
|
+
this.columnReorderService.wrapperEl.set(el);
|
|
125
|
+
});
|
|
126
|
+
// Wire column reorder service inputs
|
|
127
|
+
effect(() => {
|
|
128
|
+
const cols = this.state().layout.visibleCols;
|
|
129
|
+
this.columnReorderService.columns.set(cols);
|
|
130
|
+
this.columnReorderService.columnOrder.set(this.columnOrder());
|
|
131
|
+
this.columnReorderService.onColumnOrderChange.set(this.onColumnOrderChange());
|
|
132
|
+
this.columnReorderService.enabled.set(!!this.onColumnOrderChange());
|
|
133
|
+
});
|
|
134
|
+
// Wire virtual scroll service inputs
|
|
135
|
+
effect(() => {
|
|
136
|
+
this.virtualScrollService.totalRows.set(this.items().length);
|
|
116
137
|
});
|
|
117
138
|
// Initialize column sizing from initial widths
|
|
118
139
|
effect(() => {
|
|
@@ -133,79 +154,17 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
133
154
|
}
|
|
134
155
|
getFilterConfig(col) {
|
|
135
156
|
const s = this.state();
|
|
136
|
-
|
|
137
|
-
const filterable = col.filterable && typeof col.filterable === 'object' ? col.filterable : null;
|
|
138
|
-
const filterType = filterable?.type ?? 'none';
|
|
139
|
-
const filterField = filterable?.filterField ?? col.columnId;
|
|
140
|
-
const sortable = col.sortable !== false;
|
|
141
|
-
const filterValue = hfi.filters[filterField];
|
|
142
|
-
const base = {
|
|
143
|
-
filterType,
|
|
144
|
-
isSorted: hfi.sortBy === col.columnId,
|
|
145
|
-
isSortedDescending: hfi.sortBy === col.columnId && hfi.sortDirection === 'desc',
|
|
146
|
-
onSort: sortable ? () => hfi.onColumnSort(col.columnId) : undefined,
|
|
147
|
-
};
|
|
148
|
-
if (filterType === 'text') {
|
|
149
|
-
return {
|
|
150
|
-
...base,
|
|
151
|
-
textValue: filterValue?.type === 'text' ? filterValue.value : '',
|
|
152
|
-
onTextChange: (v) => hfi.onFilterChange(filterField, v.trim() ? { type: 'text', value: v } : undefined),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
if (filterType === 'multiSelect') {
|
|
156
|
-
return {
|
|
157
|
-
...base,
|
|
158
|
-
options: hfi.filterOptions[filterField] ?? [],
|
|
159
|
-
isLoadingOptions: hfi.loadingFilterOptions[filterField] ?? false,
|
|
160
|
-
selectedValues: filterValue?.type === 'multiSelect' ? filterValue.value : [],
|
|
161
|
-
onFilterChange: (values) => hfi.onFilterChange(filterField, values.length ? { type: 'multiSelect', value: values } : undefined),
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (filterType === 'people') {
|
|
165
|
-
return {
|
|
166
|
-
...base,
|
|
167
|
-
selectedUser: filterValue?.type === 'people' ? filterValue.value : undefined,
|
|
168
|
-
onUserChange: (u) => hfi.onFilterChange(filterField, u ? { type: 'people', value: u } : undefined),
|
|
169
|
-
peopleSearch: hfi.peopleSearch,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
if (filterType === 'date') {
|
|
173
|
-
return {
|
|
174
|
-
...base,
|
|
175
|
-
dateValue: filterValue?.type === 'date' ? filterValue.value : undefined,
|
|
176
|
-
onDateChange: (v) => hfi.onFilterChange(filterField, v ? { type: 'date', value: v } : undefined),
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
return base;
|
|
157
|
+
return getHeaderFilterConfig(col, s.viewModels.headerFilterInput);
|
|
180
158
|
}
|
|
181
159
|
getCellValueFn(item, col) {
|
|
182
160
|
return getCellValue(item, col);
|
|
183
161
|
}
|
|
184
162
|
resolveCellDisplay(col, item) {
|
|
185
|
-
if (col.renderCell && typeof col.renderCell === 'function') {
|
|
186
|
-
const result = col.renderCell(item);
|
|
187
|
-
return result ?? '';
|
|
188
|
-
}
|
|
189
163
|
const value = getCellValue(item, col);
|
|
190
|
-
|
|
191
|
-
return String(col.valueFormatter(value, item) ?? '');
|
|
192
|
-
if (value == null)
|
|
193
|
-
return '';
|
|
194
|
-
if (col.type === 'date') {
|
|
195
|
-
const d = new Date(String(value));
|
|
196
|
-
if (!Number.isNaN(d.getTime()))
|
|
197
|
-
return d.toLocaleDateString();
|
|
198
|
-
}
|
|
199
|
-
if (col.type === 'boolean')
|
|
200
|
-
return value ? 'True' : 'False';
|
|
201
|
-
return String(value);
|
|
164
|
+
return resolveCellDisplayContent(col, item, value);
|
|
202
165
|
}
|
|
203
166
|
getCellStyleObj(col, item) {
|
|
204
|
-
|
|
205
|
-
return null;
|
|
206
|
-
return typeof col.cellStyle === 'function'
|
|
207
|
-
? col.cellStyle(item)
|
|
208
|
-
: col.cellStyle;
|
|
167
|
+
return resolveCellStyle(col, item) ?? null;
|
|
209
168
|
}
|
|
210
169
|
canEditCell(col, item) {
|
|
211
170
|
const colEditable = col.editable === true || (typeof col.editable === 'function' && col.editable(item));
|
|
@@ -297,6 +256,9 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
297
256
|
handlePaste() {
|
|
298
257
|
void this.state().interaction.handlePaste();
|
|
299
258
|
}
|
|
259
|
+
onHeaderMouseDown(columnId, event) {
|
|
260
|
+
this.columnReorderService.handleHeaderMouseDown(columnId, event);
|
|
261
|
+
}
|
|
300
262
|
onResizeStart(e, col) {
|
|
301
263
|
e.preventDefault();
|
|
302
264
|
this.resizeStartX = e.clientX;
|
|
@@ -307,6 +269,7 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
307
269
|
const minW = col.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;
|
|
308
270
|
const newWidth = Math.max(minW, this.resizeStartWidth + delta);
|
|
309
271
|
this.columnSizingOverrides.update((prev) => ({ ...prev, [this.resizeColumnId]: newWidth }));
|
|
272
|
+
this.columnSizingVersion.update(v => v + 1);
|
|
310
273
|
};
|
|
311
274
|
const onUp = () => {
|
|
312
275
|
window.removeEventListener('mousemove', onMove, true);
|
|
@@ -324,6 +287,24 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
324
287
|
window.addEventListener('mousemove', onMove, true);
|
|
325
288
|
window.addEventListener('mouseup', onUp, true);
|
|
326
289
|
}
|
|
290
|
+
// --- Column pinning methods ---
|
|
291
|
+
onPinColumn(columnId, side) {
|
|
292
|
+
this.onColumnPinned()?.(columnId, side);
|
|
293
|
+
}
|
|
294
|
+
onUnpinColumn(columnId) {
|
|
295
|
+
this.onColumnPinned()?.(columnId, null);
|
|
296
|
+
}
|
|
297
|
+
isPinned(columnId) {
|
|
298
|
+
return this.pinnedColumns()?.[columnId];
|
|
299
|
+
}
|
|
300
|
+
getPinState(columnId) {
|
|
301
|
+
const pinned = this.isPinned(columnId);
|
|
302
|
+
return {
|
|
303
|
+
canPinLeft: pinned !== 'left',
|
|
304
|
+
canPinRight: pinned !== 'right',
|
|
305
|
+
canUnpin: !!pinned,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
327
308
|
buildProps() {
|
|
328
309
|
return {
|
|
329
310
|
items: this.items(),
|
|
@@ -355,6 +336,9 @@ let DataGridTableComponent = class DataGridTableComponent {
|
|
|
355
336
|
rowSelection: this.rowSelectionMode(),
|
|
356
337
|
selectedRows: this.selectedRows(),
|
|
357
338
|
onSelectionChange: this.onSelectionChange(),
|
|
339
|
+
showRowNumbers: this.showRowNumbers(),
|
|
340
|
+
currentPage: this.currentPage(),
|
|
341
|
+
pageSize: this.pageSize(),
|
|
358
342
|
statusBar: this.statusBar(),
|
|
359
343
|
filters: this.filters(),
|
|
360
344
|
onFilterChange: this.onFilterChange(),
|
|
@@ -380,6 +364,7 @@ DataGridTableComponent = __decorate([
|
|
|
380
364
|
MarchingAntsOverlayComponent,
|
|
381
365
|
EmptyStateComponent,
|
|
382
366
|
ColumnHeaderFilterComponent,
|
|
367
|
+
ColumnHeaderMenuComponent,
|
|
383
368
|
InlineCellEditorComponent,
|
|
384
369
|
],
|
|
385
370
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -433,6 +418,18 @@ DataGridTableComponent = __decorate([
|
|
|
433
418
|
@if (rowIdx === 0 && rowIdx < headerRows().length - 1 && state().layout.hasCheckboxCol) {
|
|
434
419
|
<th [attr.rowSpan]="headerRows().length - 1"></th>
|
|
435
420
|
}
|
|
421
|
+
@if (rowIdx === headerRows().length - 1 && state().layout.hasRowNumbersCol) {
|
|
422
|
+
<th
|
|
423
|
+
scope="col"
|
|
424
|
+
rowSpan="1"
|
|
425
|
+
style="width:50px;min-width:50px;max-width:50px;padding:6px;text-align:center;font-weight:600;background:var(--ogrid-bg-subtle,#fafafa);color:var(--ogrid-text-secondary,#666);border-bottom:1px solid var(--ogrid-border,#e0e0e0);position:sticky;left:0;z-index:4"
|
|
426
|
+
>
|
|
427
|
+
#
|
|
428
|
+
</th>
|
|
429
|
+
}
|
|
430
|
+
@if (rowIdx === 0 && rowIdx < headerRows().length - 1 && state().layout.hasRowNumbersCol) {
|
|
431
|
+
<th [attr.rowSpan]="headerRows().length - 1" style="width:50px;min-width:50px"></th>
|
|
432
|
+
}
|
|
436
433
|
@for (cell of row; track $index; let cellIdx = $index) {
|
|
437
434
|
@if (cell.isGroup) {
|
|
438
435
|
<th
|
|
@@ -443,34 +440,51 @@ DataGridTableComponent = __decorate([
|
|
|
443
440
|
{{ cell.label }}
|
|
444
441
|
</th>
|
|
445
442
|
} @else {
|
|
443
|
+
@let pinned = isPinned(cell.columnDef!.columnId);
|
|
446
444
|
<th
|
|
447
445
|
scope="col"
|
|
448
446
|
[attr.data-column-id]="cell.columnDef!.columnId"
|
|
449
447
|
[attr.rowSpan]="headerRows().length > 1 && rowIdx < headerRows().length - 1 ? headerRows().length - rowIdx : null"
|
|
448
|
+
[class.ogrid-th-pinned-left]="pinned === 'left'"
|
|
449
|
+
[class.ogrid-th-pinned-right]="pinned === 'right'"
|
|
450
450
|
style="padding:6px 8px;text-align:left;font-weight:600;border-bottom:1px solid var(--ogrid-border, #e0e0e0);position:relative"
|
|
451
451
|
[style.min-width.px]="cell.columnDef!.minWidth ?? defaultMinWidth"
|
|
452
452
|
[style.width.px]="getColumnWidth(cell.columnDef!)"
|
|
453
453
|
[style.max-width.px]="getColumnWidth(cell.columnDef!)"
|
|
454
|
+
[style.cursor]="columnReorderService.isDragging() ? 'grabbing' : 'grab'"
|
|
455
|
+
(mousedown)="onHeaderMouseDown(cell.columnDef!.columnId, $event)"
|
|
454
456
|
>
|
|
455
|
-
<
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
457
|
+
<div style="display:flex;align-items:center;gap:4px;">
|
|
458
|
+
<ogrid-primeng-column-header-filter
|
|
459
|
+
[columnKey]="cell.columnDef!.columnId"
|
|
460
|
+
[columnName]="cell.columnDef!.name"
|
|
461
|
+
[filterType]="getFilterConfig(cell.columnDef!).filterType"
|
|
462
|
+
[isSorted]="getFilterConfig(cell.columnDef!).isSorted ?? false"
|
|
463
|
+
[isSortedDescending]="getFilterConfig(cell.columnDef!).isSortedDescending ?? false"
|
|
464
|
+
[onSort]="getFilterConfig(cell.columnDef!).onSort"
|
|
465
|
+
[selectedValues]="getFilterConfig(cell.columnDef!).selectedValues"
|
|
466
|
+
[onFilterChange]="getFilterConfig(cell.columnDef!).onFilterChange"
|
|
467
|
+
[options]="getFilterConfig(cell.columnDef!).options ?? []"
|
|
468
|
+
[isLoadingOptions]="getFilterConfig(cell.columnDef!).isLoadingOptions ?? false"
|
|
469
|
+
[textValue]="getFilterConfig(cell.columnDef!).textValue ?? ''"
|
|
470
|
+
[onTextChange]="getFilterConfig(cell.columnDef!).onTextChange"
|
|
471
|
+
[selectedUser]="getFilterConfig(cell.columnDef!).selectedUser"
|
|
472
|
+
[onUserChange]="getFilterConfig(cell.columnDef!).onUserChange"
|
|
473
|
+
[peopleSearch]="getFilterConfig(cell.columnDef!).peopleSearch"
|
|
474
|
+
[dateValue]="getFilterConfig(cell.columnDef!).dateValue"
|
|
475
|
+
[onDateChange]="getFilterConfig(cell.columnDef!).onDateChange"
|
|
476
|
+
></ogrid-primeng-column-header-filter>
|
|
477
|
+
@let pinState = getPinState(cell.columnDef!.columnId);
|
|
478
|
+
<column-header-menu
|
|
479
|
+
[columnId]="cell.columnDef!.columnId"
|
|
480
|
+
[onPinLeft]="() => onPinColumn(cell.columnDef!.columnId, 'left')"
|
|
481
|
+
[onPinRight]="() => onPinColumn(cell.columnDef!.columnId, 'right')"
|
|
482
|
+
[onUnpin]="() => onUnpinColumn(cell.columnDef!.columnId)"
|
|
483
|
+
[canPinLeft]="pinState.canPinLeft"
|
|
484
|
+
[canPinRight]="pinState.canPinRight"
|
|
485
|
+
[canUnpin]="pinState.canUnpin"
|
|
486
|
+
/>
|
|
487
|
+
</div>
|
|
474
488
|
<div
|
|
475
489
|
style="position:absolute;top:0;right:0;bottom:0;width:4px;cursor:col-resize"
|
|
476
490
|
(mousedown)="onResizeStart($event, cell.columnDef!)"
|
|
@@ -506,8 +520,18 @@ DataGridTableComponent = __decorate([
|
|
|
506
520
|
/>
|
|
507
521
|
</td>
|
|
508
522
|
}
|
|
523
|
+
@if (state().layout.hasRowNumbersCol) {
|
|
524
|
+
<td
|
|
525
|
+
style="width:50px;min-width:50px;max-width:50px;padding:6px;text-align:center;font-weight:600;font-variant-numeric:tabular-nums;color:var(--ogrid-text-secondary,#666);background:var(--ogrid-bg-subtle,#fafafa);border-bottom:1px solid var(--ogrid-border,#f0f0f0);position:sticky;left:0;z-index:3"
|
|
526
|
+
>
|
|
527
|
+
{{ rowNumberOffset() + rowIndex + 1 }}
|
|
528
|
+
</td>
|
|
529
|
+
}
|
|
509
530
|
@for (col of state().layout.visibleCols; track col.columnId; let colIdx = $index) {
|
|
531
|
+
@let pinned = isPinned(col.columnId);
|
|
510
532
|
<td
|
|
533
|
+
[class.ogrid-td-pinned-left]="pinned === 'left'"
|
|
534
|
+
[class.ogrid-td-pinned-right]="pinned === 'right'"
|
|
511
535
|
style="padding:0;border-bottom:1px solid var(--ogrid-border, #f0f0f0);position:relative"
|
|
512
536
|
[style.min-width.px]="col.minWidth ?? defaultMinWidth"
|
|
513
537
|
[style.width.px]="getColumnWidth(col)"
|
|
@@ -561,6 +585,7 @@ DataGridTableComponent = __decorate([
|
|
|
561
585
|
[copyRange]="state().interaction.copyRange"
|
|
562
586
|
[cutRange]="state().interaction.cutRange"
|
|
563
587
|
[colOffset]="state().layout.colOffset"
|
|
588
|
+
[columnSizingVersion]="columnSizingVersion()"
|
|
564
589
|
></ogrid-marching-ants-overlay>
|
|
565
590
|
|
|
566
591
|
@if (state().viewModels.showEmptyInGrid && emptyState()) {
|
|
@@ -581,6 +606,10 @@ DataGridTableComponent = __decorate([
|
|
|
581
606
|
</div>
|
|
582
607
|
</div>
|
|
583
608
|
|
|
609
|
+
@if (columnReorderService.isDragging() && columnReorderService.dropIndicatorX() !== null) {
|
|
610
|
+
<div class="ogrid-drop-indicator" [style.left.px]="columnReorderService.dropIndicatorX()"></div>
|
|
611
|
+
}
|
|
612
|
+
|
|
584
613
|
@if (state().contextMenu.menuPosition) {
|
|
585
614
|
<ogrid-context-menu
|
|
586
615
|
[x]="state().contextMenu.menuPosition!.x"
|
|
@@ -627,6 +656,44 @@ DataGridTableComponent = __decorate([
|
|
|
627
656
|
opacity: 0.5;
|
|
628
657
|
pointer-events: none;
|
|
629
658
|
}
|
|
659
|
+
.ogrid-drop-indicator {
|
|
660
|
+
position: absolute;
|
|
661
|
+
top: 0;
|
|
662
|
+
bottom: 0;
|
|
663
|
+
width: 3px;
|
|
664
|
+
background: var(--ogrid-primary, #217346);
|
|
665
|
+
pointer-events: none;
|
|
666
|
+
z-index: 100;
|
|
667
|
+
transition: left 0.05s;
|
|
668
|
+
}
|
|
669
|
+
.ogrid-th-pinned-left {
|
|
670
|
+
position: sticky;
|
|
671
|
+
left: 0;
|
|
672
|
+
z-index: 10;
|
|
673
|
+
background: var(--ogrid-header-bg, #f5f5f5);
|
|
674
|
+
border-left: 2px solid var(--ogrid-primary, #217346);
|
|
675
|
+
}
|
|
676
|
+
.ogrid-th-pinned-right {
|
|
677
|
+
position: sticky;
|
|
678
|
+
right: 0;
|
|
679
|
+
z-index: 10;
|
|
680
|
+
background: var(--ogrid-header-bg, #f5f5f5);
|
|
681
|
+
border-right: 2px solid var(--ogrid-primary, #217346);
|
|
682
|
+
}
|
|
683
|
+
.ogrid-td-pinned-left {
|
|
684
|
+
position: sticky;
|
|
685
|
+
left: 0;
|
|
686
|
+
z-index: 5;
|
|
687
|
+
background: var(--ogrid-bg, #fff);
|
|
688
|
+
border-left: 2px solid var(--ogrid-primary, #217346);
|
|
689
|
+
}
|
|
690
|
+
.ogrid-td-pinned-right {
|
|
691
|
+
position: sticky;
|
|
692
|
+
right: 0;
|
|
693
|
+
z-index: 5;
|
|
694
|
+
background: var(--ogrid-bg, #fff);
|
|
695
|
+
border-right: 2px solid var(--ogrid-primary, #217346);
|
|
696
|
+
}
|
|
630
697
|
`],
|
|
631
698
|
})
|
|
632
699
|
], DataGridTableComponent);
|
|
@@ -70,6 +70,14 @@ let InlineCellEditorComponent = class InlineCellEditorComponent {
|
|
|
70
70
|
onTextBlur() {
|
|
71
71
|
this.commitValue(this.localValue());
|
|
72
72
|
}
|
|
73
|
+
getInputStyle() {
|
|
74
|
+
const baseStyle = 'width:100%;box-sizing:border-box;padding:6px 10px;border:2px solid var(--ogrid-selection, #217346);border-radius:2px;outline:none;font:inherit;background:var(--ogrid-bg, #fff);color:var(--ogrid-fg, #242424);';
|
|
75
|
+
const col = this.column();
|
|
76
|
+
if (col.type === 'numeric') {
|
|
77
|
+
return baseStyle + 'text-align:right;';
|
|
78
|
+
}
|
|
79
|
+
return baseStyle;
|
|
80
|
+
}
|
|
73
81
|
};
|
|
74
82
|
InlineCellEditorComponent = __decorate([
|
|
75
83
|
Component({
|
|
@@ -86,7 +94,7 @@ InlineCellEditorComponent = __decorate([
|
|
|
86
94
|
(input)="localValue.set($any($event.target).value)"
|
|
87
95
|
(keydown)="onTextKeyDown($event)"
|
|
88
96
|
(blur)="onTextBlur()"
|
|
89
|
-
style="
|
|
97
|
+
[style]="getInputStyle()"
|
|
90
98
|
/>
|
|
91
99
|
}
|
|
92
100
|
@case ('select') {
|
|
@@ -122,7 +130,7 @@ InlineCellEditorComponent = __decorate([
|
|
|
122
130
|
(change)="commitValue($any($event.target).value)"
|
|
123
131
|
(keydown)="onTextKeyDown($event)"
|
|
124
132
|
(blur)="onTextBlur()"
|
|
125
|
-
style="
|
|
133
|
+
[style]="getInputStyle()"
|
|
126
134
|
/>
|
|
127
135
|
}
|
|
128
136
|
@default {
|
|
@@ -133,7 +141,7 @@ InlineCellEditorComponent = __decorate([
|
|
|
133
141
|
(input)="localValue.set($any($event.target).value)"
|
|
134
142
|
(keydown)="onTextKeyDown($event)"
|
|
135
143
|
(blur)="onTextBlur()"
|
|
136
|
-
style="
|
|
144
|
+
[style]="getInputStyle()"
|
|
137
145
|
/>
|
|
138
146
|
}
|
|
139
147
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -7,3 +7,4 @@ export { InlineCellEditorComponent } from './datagrid-table/inline-cell-editor.c
|
|
|
7
7
|
export { ColumnHeaderFilterComponent } from './column-header-filter/column-header-filter.component';
|
|
8
8
|
export { ColumnChooserComponent } from './column-chooser/column-chooser.component';
|
|
9
9
|
export { PaginationControlsComponent } from './pagination-controls/pagination-controls.component';
|
|
10
|
+
export { ColumnHeaderMenuComponent } from './column-header-menu/column-header-menu.component';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import type { Menu } from 'primeng/menu';
|
|
3
|
+
import type { MenuItem } from 'primeng/api';
|
|
4
|
+
/**
|
|
5
|
+
* Column header dropdown menu for pin/unpin actions.
|
|
6
|
+
* Uses PrimeNG Menu component.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ColumnHeaderMenuComponent {
|
|
9
|
+
columnId: string;
|
|
10
|
+
set canPinLeft(value: boolean);
|
|
11
|
+
set canPinRight(value: boolean);
|
|
12
|
+
set canUnpin(value: boolean);
|
|
13
|
+
pinLeft: EventEmitter<void>;
|
|
14
|
+
pinRight: EventEmitter<void>;
|
|
15
|
+
unpin: EventEmitter<void>;
|
|
16
|
+
menu: Menu;
|
|
17
|
+
private _canPinLeft;
|
|
18
|
+
private _canPinRight;
|
|
19
|
+
private _canUnpin;
|
|
20
|
+
menuModel: MenuItem[];
|
|
21
|
+
ngOnInit(): void;
|
|
22
|
+
private updateMenuModel;
|
|
23
|
+
handlePinLeft(): void;
|
|
24
|
+
handlePinRight(): void;
|
|
25
|
+
handleUnpin(): void;
|
|
26
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { ElementRef } from '@angular/core';
|
|
2
|
-
import
|
|
2
|
+
import { ColumnReorderService, VirtualScrollService } from '@alaarab/ogrid-angular';
|
|
3
|
+
import type { IColumnDef, IColumnGroupDef, RowId, HeaderFilterConfig } from '@alaarab/ogrid-angular';
|
|
3
4
|
export declare class DataGridTableComponent<T = unknown> {
|
|
4
5
|
private readonly stateService;
|
|
6
|
+
readonly columnReorderService: ColumnReorderService<T>;
|
|
7
|
+
readonly virtualScrollService: VirtualScrollService;
|
|
5
8
|
readonly wrapperRef: import("@angular/core").Signal<ElementRef<HTMLDivElement> | undefined>;
|
|
6
9
|
readonly tableContainerRef: import("@angular/core").Signal<ElementRef<HTMLDivElement> | undefined>;
|
|
7
10
|
readonly items: import("@angular/core").InputSignal<T[]>;
|
|
@@ -58,6 +61,9 @@ export declare class DataGridTableComponent<T = unknown> {
|
|
|
58
61
|
readonly onCellError: import("@angular/core").InputSignal<((error: Error) => void) | undefined>;
|
|
59
62
|
readonly ariaLabel: import("@angular/core").InputSignal<string | undefined>;
|
|
60
63
|
readonly ariaLabelledBy: import("@angular/core").InputSignal<string | undefined>;
|
|
64
|
+
readonly showRowNumbers: import("@angular/core").InputSignal<boolean>;
|
|
65
|
+
readonly currentPage: import("@angular/core").InputSignal<number>;
|
|
66
|
+
readonly pageSize: import("@angular/core").InputSignal<number>;
|
|
61
67
|
readonly defaultMinWidth = 80;
|
|
62
68
|
readonly statusBarClasses: {
|
|
63
69
|
statusBar: string;
|
|
@@ -70,40 +76,20 @@ export declare class DataGridTableComponent<T = unknown> {
|
|
|
70
76
|
private resizeColumnId;
|
|
71
77
|
private resizeStartWidth;
|
|
72
78
|
private lastMouseShift;
|
|
79
|
+
private columnSizingVersion;
|
|
73
80
|
constructor();
|
|
74
81
|
readonly state: import("@angular/core").Signal<import("@alaarab/ogrid-angular").DataGridStateResult<T>>;
|
|
75
82
|
readonly tableContainerEl: import("@angular/core").Signal<HTMLDivElement | null>;
|
|
76
83
|
readonly resolvedAriaLabel: import("@angular/core").Signal<string | undefined>;
|
|
77
|
-
readonly
|
|
84
|
+
readonly rowNumberOffset: import("@angular/core").Signal<number>;
|
|
85
|
+
readonly headerRows: import("@angular/core").Signal<import("@alaarab/ogrid-core").HeaderRow<T>[]>;
|
|
78
86
|
readonly allowOverflowX: import("@angular/core").Signal<boolean>;
|
|
79
87
|
readonly tableWidthStyle: import("@angular/core").Signal<"100%" | "fit-content">;
|
|
80
88
|
readonly tableMinWidthStyle: import("@angular/core").Signal<"100%" | "max-content">;
|
|
81
89
|
readonly selectedCellCount: import("@angular/core").Signal<number | undefined>;
|
|
82
90
|
trackByRowId(_index: number, item: T): RowId;
|
|
83
91
|
getColumnWidth(col: IColumnDef<T>): number | undefined;
|
|
84
|
-
getFilterConfig(col: IColumnDef<T>):
|
|
85
|
-
filterType: string;
|
|
86
|
-
isSorted?: boolean;
|
|
87
|
-
isSortedDescending?: boolean;
|
|
88
|
-
onSort?: () => void;
|
|
89
|
-
selectedValues?: string[];
|
|
90
|
-
onFilterChange?: (values: string[]) => void;
|
|
91
|
-
options?: string[];
|
|
92
|
-
isLoadingOptions?: boolean;
|
|
93
|
-
textValue?: string;
|
|
94
|
-
onTextChange?: (value: string) => void;
|
|
95
|
-
selectedUser?: unknown;
|
|
96
|
-
onUserChange?: (user: unknown) => void;
|
|
97
|
-
peopleSearch?: (query: string) => Promise<unknown[]>;
|
|
98
|
-
dateValue?: {
|
|
99
|
-
from?: string;
|
|
100
|
-
to?: string;
|
|
101
|
-
};
|
|
102
|
-
onDateChange?: (value: {
|
|
103
|
-
from?: string;
|
|
104
|
-
to?: string;
|
|
105
|
-
} | undefined) => void;
|
|
106
|
-
};
|
|
92
|
+
getFilterConfig(col: IColumnDef<T>): HeaderFilterConfig;
|
|
107
93
|
getCellValueFn(item: T, col: IColumnDef<T>): unknown;
|
|
108
94
|
resolveCellDisplay(col: IColumnDef<T>, item: T): string;
|
|
109
95
|
getCellStyleObj(col: IColumnDef<T>, item: T): Record<string, string> | null;
|
|
@@ -125,6 +111,15 @@ export declare class DataGridTableComponent<T = unknown> {
|
|
|
125
111
|
onRowClick(e: MouseEvent, item: T): void;
|
|
126
112
|
onRowCheckboxChange(item: T, checked: boolean, rowIndex: number, e: Event): void;
|
|
127
113
|
handlePaste(): void;
|
|
114
|
+
onHeaderMouseDown(columnId: string, event: MouseEvent): void;
|
|
128
115
|
onResizeStart(e: MouseEvent, col: IColumnDef<T>): void;
|
|
116
|
+
onPinColumn(columnId: string, side: 'left' | 'right'): void;
|
|
117
|
+
onUnpinColumn(columnId: string): void;
|
|
118
|
+
isPinned(columnId: string): 'left' | 'right' | undefined;
|
|
119
|
+
getPinState(columnId: string): {
|
|
120
|
+
canPinLeft: boolean;
|
|
121
|
+
canPinRight: boolean;
|
|
122
|
+
canUnpin: boolean;
|
|
123
|
+
};
|
|
129
124
|
private buildProps;
|
|
130
125
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export { InlineCellEditorComponent } from './datagrid-table/inline-cell-editor.c
|
|
|
5
5
|
export { ColumnHeaderFilterComponent } from './column-header-filter/column-header-filter.component';
|
|
6
6
|
export { ColumnChooserComponent } from './column-chooser/column-chooser.component';
|
|
7
7
|
export { PaginationControlsComponent } from './pagination-controls/pagination-controls.component';
|
|
8
|
+
export { ColumnHeaderMenuComponent } from './column-header-menu/column-header-menu.component';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-angular-primeng",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "OGrid PrimeNG – PrimeNG Table-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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"files": ["dist", "README.md", "LICENSE"],
|
|
23
23
|
"engines": { "node": ">=18" },
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@alaarab/ogrid-angular": "2.0.
|
|
25
|
+
"@alaarab/ogrid-angular": "2.0.4"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"@angular/core": "^21.0.0",
|